The actual crash you get is an EXC_BAD_ACCESS when the key value observing dictionary is accesed. The stack trace is as follows:

* thread #2: tid = 0x1ade39, 0x00007fff92f8e097 libobjc.A.dylib`objc_msgSend + 23, queue = 'com.apple.root.default-priority', stop reason = EXC_BAD_ACCESS (code=1, address=0x18) frame #0: 0x00007fff92f8e097 libobjc.A.dylib`objc_msgSend + 23 frame #1: 0x00007fff8ffe2b11 CoreFoundation`CFDictionaryGetValue + 145 frame #2: 0x00007fff8dc55750 Foundation`NSKVOUnionSetAndNotify + 147 * frame #3: 0x0000000100000f85 TestApp`__19-[TestObject start]_block_invoke(.block_descriptor=<unavailable>) + 165 at main.m:34 frame #4: 0x000000010001832d libdispatch.dylib`_dispatch_call_block_and_release + 12 frame #5: 0x0000000100014925 libdispatch.dylib`_dispatch_client_callout + 8 frame #6: 0x0000000100016c3d libdispatch.dylib`_dispatch_root_queue_drain + 601 frame #7: 0x00000001000182e6 libdispatch.dylib`_dispatch_worker_thread2 + 52 frame #8: 0x00007fff9291eef8 libsystem_pthread.dylib`_pthread_wqthread + 314 frame #9: 0x00007fff92921fb9 libsystem_pthread.dylib`start_wqthread + 13

If you set a symbolic breakpoint with the symbol NSKVOUnionSetAndNotify the debugger will stop where this method is being invoked. The crash you are seeing is because automatic key-value notifications are being sent from one thread when you invoke your [addFoos:] method, but then the change dictionary is being accessed from another thread. This is stimulated by your use of the global dispatch queue when calling this method, as that will execute the block in many different threads.

There are mulitple ways to fix this crash, and I will try to walk you through this to give you a more thourough understanding of what is going on.

In the simplest case, you can fix the crash by using the key-value coding mutable proxy object for this key:

NSMutableSet *someSet = [self mutableSetValueForKey:@"foos"]; [someSet unionSet:[NSSet setWithObject:@(rand() % 100)]];

That will stop this particular crash. What's happening here? When mutableSetValueForKey: is called, the result is a proxy object that forwards messages to your KVC-compliant accessor methods for the key "foos". The author's object does not actually fully conform to the required pattern for a KVC compliant property of this type. If other KVC accessor methods are messaged for this key, they may go through non-thread safe accessors provided by Foundation, which can result in this crash all over again. We'll get to how to fix that in a moment.

The crash is being triggered by automatic KVO change notifications crossing threads. Automatic KVO notifications work by swizzling classes and methods at runtime. You can read a more in-depth explanation here and here. KVC accessor methods are essentially wrapped at runtime with KVO-supplied methods. This is in fact where the crash in the original application is happening. This is the KVO inserted code disassembled from Foundation:

int _NSKVOUnionSetAndNotify(int arg0, int arg1, int arg2) { r4 = object_getIndexedIvars(object_getClass(arg0)); OSSpinLockLock(_NSKVONotifyingInfoPropertyKeysSpinLock); r6 = CFDictionaryGetValue(*(r4 + 0xc), arg1); OSSpinLockUnlock(_NSKVONotifyingInfoPropertyKeysSpinLock); var_0 = arg2; [arg0 willChangeValueForKey:r6 withSetMutation:0x1 usingObjects:STK-1]; r0 = *r4; r0 = class_getInstanceMethod(r0, arg1); method_invoke(arg0, r0); var_0 = arg2; r0 = [arg0 didChangeValueForKey:r6 withSetMutation:0x1 usingObjects:STK-1]; Pop(); Pop(); Pop(); return r0; }

As you can see, this is wrapping a KVC compliant accessor method with willChangeValueForKey:withSetMutation:usingObjects: and didChangeValueForKey: withSetMutation:usingObjects: . These are the methods that send out KVO notifications. KVO will insert this wrapper at runtime if the object has opted into automatic key value observer notification. In between these calls you can see class_getInstanceMethod . This is getting a reference to the KVC compliant accessor being wrapped, and then calling it. In the case of the original code, this is being triggered from inside NSSet's unionSet: , which was happening across threads and causing the crash when it accessed the change dictionary.

Automatic notifications are sent by the thread where the change occured, and are intended to be received on the same thread. This being Teh IntarWebs, there is a lot of bad or misleading information out there about KVO. Not all objects and not all properties emit automatic KVO notifications, and in your classes you can control which do and don't. From the Key Value Observing Programming Guide: Automatic Change Notification :

NSObject provides a basic implementation of automatic key-value change notification. Automatic key-value change notification informs observers of changes made using key-value compliant accessors, as well as the key-value coding methods. Automatic notification is also supported by the collection proxy objects returned by, for example, mutableArrayValueForKey:

This may lead one to believe that all descendants of NSObject emit automatic notifications by default. This is not the case - may framework classes do not, or implement special behavior. Core Data is an example. From the Core Data Programming Guide :

NSManagedObject disables automatic key-value observing (KVO) change notifications for modeled properties, and the primitive accessor methods do not invoke the access and change notification methods. For unmodeled properties, on OS X v10.4 Core Data also disables automatic KVO; on OS X v10.5 and later, Core Data adopts to NSObject’s behavior.

As a developer, you can ensure that automatic key value observer notifications are on or off for a particular property by implementing a method with the correct naming convention, +automaticallyNotifiesObserversOf<Key> . When this method returns NO, automatic key value notifications are not emitted for this property. When automatic change notifications are disabled KVO also does not have to swizzle the accessor method at runtime, as this is done primarily to support automatic change notifications. For example:

+ (BOOL) automaticallyNotifiesObserversOfFoos { return NO; }

In a comment the author stated that the reason he was using dispatch_barrier_sync for his accessor methods is that if he did not, KVO notifications would arrive before changes occured. With automatic notifications disabled for a property, you still have the option of sending these notifications manually. This is done by using the methods willChangeValueForKey: and didChangeValueForKey: . Not only does this give you control of when these notifications are sent (if at all), but on what thread. Automatic change notifications, as you recall, are sent from and received on the thread where the change occured. For example, if you wanted change notifications to happen only on the main queue, you could do so using recursive decomposition:

- (void)addFoos:(NSSet *)objects { dispatch_async(dispatch_get_main_queue(), ^{ [self willChangeValueForKey:@"foos"]; dispatch_barrier_sync(queue, ^{ [_internalFoos unionSet:objects]; dispatch_async(dispatch_get_main_queue(), ^{ [self didChangeValueForKey:@"foos"]; }); }); }); }

The original class in the author's question was forcing KVO observation to start and stop on the main queue, which seems have been an attempt to emit notifications on the main queue. The above example demonstrates a solution that not only addresses that concern, but ensures that the KVO notifications are correctly sent before and after the data changes.

In the example above I modified the author's original method as an illustrative example - this class is still not correctly KVC compliant for the key "foos". To be Key-Value Observing compliant, an object must first be Key-Value Coding compliant. To address this, first create the correct Key-value coding compliant accessors for an unordered mutable collection :

Immutable: countOfFoos enumeratorOfFoos memberOfFoos:

Mutable: addFoosObject: removeFoosObject:

These are just the minimum, there are additional methods that can be implemented for performance or data integrity reasons.

The original application was using a concurrent queue and dispatch_barrier_sync . This was dangerous, for many reasons. The approach recommended by the Concurrency Programming Guide is to instead use a serial queue. This ensures that only one thing can be touching the protected resource at a time, and it is from a consistent context. For example, two of the above methods would look like this:

- (NSUInteger)countOfFoos { __block NSUInteger result = 0; dispatch_sync([self serialQueue], ^{ result = [[self internalFoos] count]; }); return result; } - (void) addFoosObject:(id)object { id addedObject = [object copy]; dispatch_async([self serialQueue], ^{ [[self internalFoos] addObject:addedObject]; }); }

Note that in this example and the next, I am not including manual KVO change notifications for brevity and clarity. If you want manual change notifications to be sent, that code should be added to these methods like what you saw in the previous example.

Unlike using dispatch_barrier_sync with a concurrent queue, this will not allow a deadlock.

The WWDC 2011 Session 210 Mastering Grand Central Dispatch showed the correct use of the dispatch barrier API for implementing a reader/writer lock for a collection using a concurrent queue. This would be implemented like this:

- (id) memberOfFoos:(id)object { __block id result = nil; dispatch_sync([self concurrentQueue], ^{ result = [[self internalFoos] member:object]; }); return result; } - (void) addFoosObject:(id)object { id addedObject = [object copy]; dispatch_barrier_async([self concurrentQueue], ^{ [[self internalFoos] addObject:addedObject]; }); }

Note that the dispatch barrier is accessed asynchronously for the write operation, while the read operation uses dispatch_sync . The original application used dispatch_barrier_sync for both reads and writes, which the author stated was done to control when automatic change notifications were sent. Using manual change notifications would address that concern (again, not shown in this example for brevity and clarity).

There are still issues with the KVO implementation in the original. It does not use the context pointer to determine ownership of an observation. This is a recommended practice, and can use a pointer to self as a value. The value should have the same address as the objected used to add and remove the observer:

[self addObserver:self forKeyPath:@"foos" options:NSKeyValueObservingOptionNew context:(void *)self]; - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == (__bridge void *)self){ // check the key path, etc. } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }

From the NSKeyValueObserving.h header:

You should use -removeObserver:forKeyPath:context: instead of -removeObserver:forKeyPath: whenever possible because it allows you to more precisely specify your intent. When the same observer is registered for the same key path multiple times, but with different context pointers each time, -removeObserver:forKeyPath: has to guess at the context pointer when deciding what exactly to remove, and it can guess wrong.

If you are interested in a further understanding of applying and implementing Key Value Observing, I suggest the video KVO Considered Awesome

In summary:

• Implement the required key-value coding accessor pattern (unordered mutable collection)

• Make those accessors thread safe (using a serial queue with dispatch_sync / dispatch_async , or a concurrent queue with dispatch_sync / dispatch_barrier_async )

• Decide wether you want automatic KVO notifications or not, implement automaticallyNotifiesObserversOfFoos accordingly

• Add manual change notifications appropriately to accessor methods