diff --git a/Source/NSKVOInternal.h b/Source/NSKVOInternal.h index b32c874c0..7748f0def 100644 --- a/Source/NSKVOInternal.h +++ b/Source/NSKVOInternal.h @@ -60,8 +60,8 @@ do \ { \ [NSException \ - raise:NSInvalidArgumentException \ - format:@"-[%s %s] is not supported. Key path: %@", \ + raise: NSInvalidArgumentException \ + format: @"-[%s %s] is not supported. Key path: %@", \ object_getClassName(self), sel_getName(_cmd), keyPath]; \ } while (false) diff --git a/Source/NSKVOSupport.m b/Source/NSKVOSupport.m index 7b741548f..9dd31562c 100644 --- a/Source/NSKVOSupport.m +++ b/Source/NSKVOSupport.m @@ -75,11 +75,11 @@ This code is licensed under the MIT License (MIT). @end @implementation _NSKVOKeyObserver -- (instancetype)initWithObject:(id)object - keypathObserver:(_NSKVOKeypathObserver *)keypathObserver - key:(NSString *)key - restOfKeypath:(NSString *)restOfKeypath - affectedObservers:(NSArray *)affectedObservers +- (instancetype)initWithObject: (id)object + keypathObserver: (_NSKVOKeypathObserver *)keypathObserver + key: (NSString *)key + restOfKeypath: (NSString *)restOfKeypath + affectedObservers: (NSArray *)affectedObservers { if (self = [super init]) { @@ -108,7 +108,7 @@ - (BOOL)isRemoved return _isRemoved; } -- (void)setIsRemoved:(BOOL)removed +- (void)setIsRemoved: (BOOL)removed { _isRemoved = removed; } @@ -124,11 +124,11 @@ - (void)setIsRemoved:(BOOL)removed @end @implementation _NSKVOKeypathObserver -- (instancetype)initWithObject:(id)object - observer:(id)observer - keyPath:(NSString *)keypath - options:(NSKeyValueObservingOptions)options - context:(void *)context +- (instancetype) initWithObject: (id)object + observer: (id)observer + keyPath: (NSString *)keypath + options: (NSKeyValueObservingOptions)options + context: (void *)context { if (self = [super init]) { @@ -141,24 +141,24 @@ - (instancetype)initWithObject:(id)object return self; } -- (void)dealloc +- (void) dealloc { [_keypath release]; [_pendingChange release]; [super dealloc]; } -- (id)observer +- (id) observer { return _observer; } -- (BOOL)pushWillChange +- (BOOL) pushWillChange { return atomic_fetch_add(&_changeDepth, 1) == 0; } -- (BOOL)popDidChange +- (BOOL) popDidChange { return atomic_fetch_sub(&_changeDepth, 1) == 1; } @@ -167,7 +167,7 @@ - (BOOL)popDidChange #pragma region Object - level Observation Info @implementation _NSKVOObservationInfo -- (instancetype)init +- (instancetype) init { if (self = [super init]) { @@ -177,7 +177,7 @@ - (instancetype)init return self; } -- (void)dealloc +- (void) dealloc { if (![self isEmpty]) { @@ -207,7 +207,7 @@ - (void)dealloc [super dealloc]; } -- (void)pushDependencyStack +- (void) pushDependencyStack { GS_MUTEX_LOCK(_lock); if (_dependencyDepth == 0) @@ -218,7 +218,7 @@ - (void)pushDependencyStack GS_MUTEX_UNLOCK(_lock); } -- (BOOL)lockDependentKeypath:(NSString *)keypath +- (BOOL) lockDependentKeypath: (NSString *)keypath { GS_MUTEX_LOCK(_lock); if ([_existingDependentKeys containsObject:keypath]) @@ -231,7 +231,7 @@ - (BOOL)lockDependentKeypath:(NSString *)keypath return YES; } -- (void)popDependencyStack +- (void) popDependencyStack { GS_MUTEX_LOCK(_lock); --_dependencyDepth; @@ -243,10 +243,11 @@ - (void)popDependencyStack GS_MUTEX_UNLOCK(_lock); } -- (void)addObserver:(_NSKVOKeyObserver *)observer +- (void) addObserver: (_NSKVOKeyObserver *)observer { NSString *key = observer.key; NSMutableArray *observersForKey = nil; + GS_MUTEX_LOCK(_lock); observersForKey = [_keyObserverMap objectForKey:key]; if (!observersForKey) @@ -258,11 +259,14 @@ - (void)addObserver:(_NSKVOKeyObserver *)observer GS_MUTEX_UNLOCK(_lock); } -- (void)removeObserver:(_NSKVOKeyObserver *)observer +- (void) removeObserver: (_NSKVOKeyObserver *)observer { + NSString *key; + NSMutableArray *observersForKey; + GS_MUTEX_LOCK(_lock); - NSString *key = observer.key; - NSMutableArray *observersForKey = [_keyObserverMap objectForKey:key]; + key = observer.key; + observersForKey = [_keyObserverMap objectForKey:key]; [observersForKey removeObject:observer]; observer.isRemoved = true; if (observersForKey.count == 0) @@ -272,18 +276,22 @@ - (void)removeObserver:(_NSKVOKeyObserver *)observer GS_MUTEX_UNLOCK(_lock); } -- (NSArray *)observersForKey:(NSString *)key +- (NSArray *) observersForKey: (NSString *)key { + NSArray *result; + GS_MUTEX_LOCK(_lock); - NSArray *result = [[[_keyObserverMap objectForKey:key] copy] autorelease]; + result = [[[_keyObserverMap objectForKey:key] copy] autorelease]; GS_MUTEX_UNLOCK(_lock); return result; } -- (bool)isEmpty +- (bool) isEmpty { + BOOL result; + GS_MUTEX_LOCK(_lock); - BOOL result = _keyObserverMap.count == 0; + result = (_keyObserverMap.count == 0); GS_MUTEX_UNLOCK(_lock); return result; } @@ -329,25 +337,27 @@ - (bool)isEmpty NSSet *valueInfluencingKeys = [cls keyPathsForValuesAffectingValueForKey: key]; if (valueInfluencingKeys.count > 0) { - // affectedKeyObservers is the list of observers that must be notified - // of changes. If we have descendants, we have to add ourselves to the - // growing list of affected keys. If not, we must pass it along - // unmodified. (This is a minor optimization: we don't need to signal - // for our own reconstruction - // if we have no subpath observers.) - NSArray *affectedKeyObservers - = (keyObserver.restOfKeypath - ? ([keyObserver.affectedObservers - arrayByAddingObject:keyObserver] - ?: [NSArray arrayWithObject:keyObserver]) - : keyObserver.affectedObservers); + NSArray *affectedKeyObservers; + NSMutableArray *dependentObservers; + + /* affectedKeyObservers is the list of observers that must be notified + * of changes. If we have descendants, we have to add ourselves to the + * growing list of affected keys. If not, we must pass it along + * unmodified. (This is a minor optimization: we don't need to signal + * for our own reconstruction + * if we have no subpath observers.) + */ + affectedKeyObservers = (keyObserver.restOfKeypath + ? ([keyObserver.affectedObservers arrayByAddingObject:keyObserver] + ?: [NSArray arrayWithObject:keyObserver]) + : keyObserver.affectedObservers); [observationInfo pushDependencyStack]; - [observationInfo - lockDependentKeypath:keyObserver.key]; // Don't allow our own key to - // be recreated. + /* Don't allow our own key to be recreated. + */ + [observationInfo lockDependentKeypath:keyObserver.key]; - NSMutableArray *dependentObservers = + dependentObservers = [NSMutableArray arrayWithCapacity:[valueInfluencingKeys count]]; for (NSString *dependentKeypath in valueInfluencingKeys) { @@ -409,28 +419,31 @@ - (bool)isEmpty static void _addKeyObserver(_NSKVOKeyObserver *keyObserver) { - id object = keyObserver.object; + _NSKVOObservationInfo *observationInfo; + id object = keyObserver.object; + _NSKVOEnsureKeyWillNotify(object, keyObserver.key); - _NSKVOObservationInfo *observationInfo + observationInfo = (__bridge _NSKVOObservationInfo *) [object observationInfo] - ?: _createObservationInfoForObject(object); + ?: _createObservationInfoForObject(object); [observationInfo addObserver:keyObserver]; } static _NSKVOKeyObserver * _addKeypathObserver(id object, NSString *keypath, - _NSKVOKeypathObserver *keyPathObserver, - NSArray *affectedObservers) + _NSKVOKeypathObserver *keyPathObserver, NSArray *affectedObservers) { + _NSKVOKeyObserver *keyObserver; + NSString *key; + NSString *restOfKeypath; + if (!object) { return nil; } - NSString *key = nil; - NSString *restOfKeypath; key = _NSKVCSplitKeypath(keypath, &restOfKeypath); - _NSKVOKeyObserver *keyObserver = + keyObserver = [[[_NSKVOKeyObserver alloc] initWithObject:object keypathObserver:keyPathObserver key:key @@ -450,7 +463,7 @@ - (bool)isEmpty #pragma region Observer / Key Deregistration static void _removeNestedObserversAndOptionallyDependents(_NSKVOKeyObserver *keyObserver, - bool dependents) + bool dependents) { if (keyObserver.restOfKeypathObserver) { @@ -496,12 +509,14 @@ - (bool)isEmpty static void _removeKeyObserver(_NSKVOKeyObserver *keyObserver) { + _NSKVOObservationInfo *observationInfo; + if (!keyObserver) { return; } - _NSKVOObservationInfo *observationInfo + observationInfo = (_NSKVOObservationInfo *) [keyObserver.object observationInfo]; [keyObserver retain]; @@ -520,29 +535,31 @@ - (bool)isEmpty static void _removeKeypathObserver(id object, NSString *keypath, id observer, void *context) { - NSString *key = nil; - NSString *restOfKeypath; + NSString *key; + NSString *restOfKeypath; + _NSKVOObservationInfo *observationInfo; + key = _NSKVCSplitKeypath(keypath, &restOfKeypath); - _NSKVOObservationInfo *observationInfo - = (_NSKVOObservationInfo *) [object observationInfo]; + observationInfo = (_NSKVOObservationInfo *) [object observationInfo]; for (_NSKVOKeyObserver *keyObserver in [observationInfo observersForKey:key]) { _NSKVOKeypathObserver *keypathObserver = keyObserver.keypathObserver; + if (keypathObserver.observer == observer - && keypathObserver.object == object && - [keypathObserver.keypath isEqual:keypath] - && (!context || keypathObserver.context == context)) + && keypathObserver.object == object + && [keypathObserver.keypath isEqual:keypath] + && (!context || keypathObserver.context == context)) { _removeKeyObserver(keyObserver); return; } } - [NSException raise:NSInvalidArgumentException - format:@"Cannot remove observer %@ for keypath \"%@\" from %@ as " - @"it is not a registered observer.", - observer, keypath, object]; + [NSException raise: NSInvalidArgumentException + format: @"Cannot remove observer %@ for keypath \"%@\" from %@" + @" as it is not a registered observer.", + observer, keypath, object]; } #pragma endregion @@ -551,49 +568,51 @@ - (bool)isEmpty @implementation NSObject (NSKeyValueObserving) -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context +- (void) observeValueForKeyPath: (NSString *)keyPath + ofObject: (id)object + change: (NSDictionary *)change + context: (void *)context { - [NSException raise:NSInternalInconsistencyException - format:@"A key-value observation notification fired, but nobody " - @"responded to it: object %@, keypath %@, change %@.", - object, keyPath, change]; + [NSException raise: NSInternalInconsistencyException + format: @"A key-value observation notification fired, but nobody " + @"responded to it: object %@, keypath %@, change %@.", + object, keyPath, change]; } static void *s_kvoObservationInfoAssociationKey; // has no value; pointer used // as an association key. -- (void *)observationInfo +- (void *) observationInfo { return (__bridge void *) objc_getAssociatedObject(self, &s_kvoObservationInfoAssociationKey); } -- (void)setObservationInfo:(void *)observationInfo +- (void) setObservationInfo: (void *)observationInfo { objc_setAssociatedObject(self, &s_kvoObservationInfoAssociationKey, - (__bridge id) observationInfo, - OBJC_ASSOCIATION_RETAIN); + (__bridge id) observationInfo, + OBJC_ASSOCIATION_RETAIN); } -+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key ++ (BOOL) automaticallyNotifiesObserversForKey: (NSString *)key { if ([key length] > 0) { - static const char *const sc_prefix = "automaticallyNotifiesObserversOf"; - static const size_t sc_prefixLength = 32; // strlen(sc_prefix) - const char *rawKey = [key UTF8String]; - size_t keyLength = strlen(rawKey); - size_t bufferSize = sc_prefixLength + keyLength + 1; - char *selectorName = (char *) malloc(bufferSize); + static const char *const sc_prefix = "automaticallyNotifiesObserversOf"; + static const size_t sc_prefixLength = 32; // strlen(sc_prefix) + const char *rawKey = [key UTF8String]; + size_t keyLength = strlen(rawKey); + size_t bufferSize = sc_prefixLength + keyLength + 1; + char *selectorName = (char *) malloc(bufferSize); + SEL sel; + memcpy(selectorName, sc_prefix, sc_prefixLength); selectorName[sc_prefixLength] = toupper(rawKey[0]); memcpy(&selectorName[sc_prefixLength + 1], &rawKey[1], keyLength); // copy keyLength characters to include terminating // NULL from rawKey - SEL sel = sel_registerName(selectorName); + sel = sel_registerName(selectorName); free(selectorName); if ([self respondsToSelector:sel]) { @@ -603,10 +622,12 @@ + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key return YES; } -+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key ++ (NSSet *) keyPathsForValuesAffectingValueForKey: (NSString *)key { - static NSSet *emptySet = nil; - static gs_mutex_t lock = GS_MUTEX_INIT_STATIC; + static NSSet *emptySet = nil; + static gs_mutex_t lock = GS_MUTEX_INIT_STATIC; + NSUInteger keyLength; + if (nil == emptySet) { GS_MUTEX_LOCK(lock); @@ -620,7 +641,7 @@ + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key // This function can be a KVO bottleneck, so it will prefer to use c string // manipulation when safe - NSUInteger keyLength = [key length]; + keyLength = [key length]; if (keyLength > 0) { static const char *const sc_prefix = "keyPathsForValuesAffecting"; @@ -644,8 +665,10 @@ + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { // fast path using c string manipulation, will cover most cases, as // most keyPaths are short - char selectorName[sc_bufferSize] - = "keyPathsForValuesAffecting"; // 26 chars + char selectorName[sc_bufferSize]; + + strncpy(selectorName, "keyPathsForValuesAffecting", 26); + selectorName[sc_prefixLength] = toupper(rawKey[0]); // Copy the rest of the key, including the null terminator memcpy(&selectorName[sc_prefixLength + 1], &rawKey[1], rawKeyLength); @@ -678,10 +701,10 @@ + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key return emptySet; } -- (void)addObserver:(id)observer - forKeyPath:(NSString *)keyPath - options:(NSKeyValueObservingOptions)options - context:(void *)context +- (void) addObserver: (id)observer + forKeyPath: (NSString *)keyPath + options: (NSKeyValueObservingOptions)options + context: (void *)context { _NSKVOKeypathObserver *keypathObserver = [[[_NSKVOKeypathObserver alloc] initWithObject:self @@ -712,13 +735,14 @@ - (void)addObserver:(id)observer } } -- (void)removeObserver:(id)observer - forKeyPath:(NSString *)keyPath - context:(void *)context +- (void) removeObserver: (id)observer + forKeyPath: (NSString *)keyPath + context: (void *)context { + _NSKVOObservationInfo *observationInfo; + _removeKeypathObserver(self, keyPath, observer, context); - _NSKVOObservationInfo *observationInfo - = (__bridge _NSKVOObservationInfo *) [self observationInfo]; + observationInfo = (__bridge _NSKVOObservationInfo *) [self observationInfo]; if ([observationInfo isEmpty]) { // TODO: was nullptr prior @@ -726,7 +750,7 @@ - (void)removeObserver:(id)observer } } -- (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath +- (void) removeObserver: (id)observer forKeyPath:(NSString *)keyPath { [self removeObserver:observer forKeyPath:keyPath context:NULL]; } @@ -785,23 +809,28 @@ - (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath = (__bridge _NSKVOObservationInfo *) [notifyingObject observationInfo]; for (_NSKVOKeyObserver *keyObserver in [observationInfo observersForKey:key]) { + _NSKVOKeypathObserver *keypathObserver; + if (keyObserver.isRemoved) { continue; } // Skip any keypaths that are in the process of changing. - _NSKVOKeypathObserver *keypathObserver = keyObserver.keypathObserver; + keypathObserver = keyObserver.keypathObserver; if ([keypathObserver pushWillChange]) { + NSKeyValueObservingOptions options; + // Call into the lambda function, which will do the actual set-up for // pendingChanges block(keyObserver); - NSKeyValueObservingOptions options = keypathObserver.options; + options = keypathObserver.options; if (options & NSKeyValueObservingOptionPrior) { NSMutableDictionary *change = keypathObserver.pendingChange; + [change setObject:@(YES) forKey:NSKeyValueChangeNotificationIsPriorKey]; [keypathObserver.observer @@ -828,6 +857,8 @@ - (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath [observationInfo observersForKey:key]; for (_NSKVOKeyObserver *keyObserver in [observers reverseObjectEnumerator]) { + _NSKVOKeypathObserver *keypathObserver; + if (keyObserver.isRemoved) { continue; @@ -837,18 +868,24 @@ - (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath _addNestedObserversAndOptionallyDependents(keyObserver, false); // Skip any keypaths that are in the process of changing. - _NSKVOKeypathObserver *keypathObserver = keyObserver.keypathObserver; + keypathObserver = keyObserver.keypathObserver; if ([keypathObserver popDidChange]) { + id observer; + NSString *keypath; + id rootObject; + NSMutableDictionary *change; + void *context; + // Call into lambda, which will do set-up for finalizing changes // dictionary block(keyObserver); - id observer = keypathObserver.observer; - NSString *keypath = keypathObserver.keypath; - id rootObject = keypathObserver.object; - NSMutableDictionary *change = keypathObserver.pendingChange; - void *context = keypathObserver.context; + observer = keypathObserver.observer; + keypath = keypathObserver.keypath; + rootObject = keypathObserver.object; + change = keypathObserver.pendingChange; + context = keypathObserver.context; [observer observeValueForKeyPath:keypath ofObject:rootObject change:change @@ -858,7 +895,7 @@ - (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath } } -- (void)willChangeValueForKey:(NSString *)key +- (void) willChangeValueForKey: (NSString *)key { if ([self observationInfo]) { @@ -884,7 +921,7 @@ - (void)willChangeValueForKey:(NSString *)key } } -- (void)didChangeValueForKey:(NSString *)key +- (void) didChangeValueForKey: (NSString *)key { if ([self observationInfo]) { @@ -906,9 +943,9 @@ - (void)didChangeValueForKey:(NSString *)key } } -- (void)willChange:(NSKeyValueChange)changeKind - valuesAtIndexes:(NSIndexSet *)indexes - forKey:(NSString *)key +- (void) willChange: (NSKeyValueChange)changeKind + valuesAtIndexes: (NSIndexSet *)indexes + forKey: (NSString *)key { __block NSKeyValueChange kind = changeKind; if ([self observationInfo]) @@ -953,9 +990,9 @@ - (void)willChange:(NSKeyValueChange)changeKind } } -- (void)didChange:(NSKeyValueChange)changeKind - valuesAtIndexes:(NSIndexSet *)indexes - forKey:(NSString *)key +- (void) didChange: (NSKeyValueChange)changeKind + valuesAtIndexes: (NSIndexSet *)indexes + forKey: (NSString *)key { if ([self observationInfo]) { @@ -986,9 +1023,9 @@ - (void)didChange:(NSKeyValueChange)changeKind static const NSString *_NSKeyValueChangeOldSetValue = @"_NSKeyValueChangeOldSetValue"; -- (void)willChangeValueForKey:(NSString *)key - withSetMutation:(NSKeyValueSetMutationKind)mutationKind - usingObjects:(NSSet *)objects +- (void)willChangeValueForKey: (NSString *)key + withSetMutation: (NSKeyValueSetMutationKind)mutationKind + usingObjects: (NSSet *)objects { if ([self observationInfo]) { @@ -1046,9 +1083,9 @@ - (void)willChangeValueForKey:(NSString *)key } } -- (void)didChangeValueForKey:(NSString *)key - withSetMutation:(NSKeyValueSetMutationKind)mutationKind - usingObjects:(NSSet *)objects +- (void)didChangeValueForKey: (NSString *)key + withSetMutation: (NSKeyValueSetMutationKind)mutationKind + usingObjects: (NSSet *)objects { if ([self observationInfo]) { @@ -1086,9 +1123,9 @@ - (void)didChangeValueForKey:(NSString *)key @implementation NSObject (NSKeyValueObservingPrivate) -- (void)_notifyObserversOfChangeForKey:(NSString *)key - oldValue:(id)oldValue - newValue:(id)newValue +- (void)_notifyObserversOfChangeForKey: (NSString *)key + oldValue: (id)oldValue + newValue: (id)newValue { if ([self observationInfo]) { @@ -1129,31 +1166,31 @@ - (void)_notifyObserversOfChangeForKey:(NSString *)key @implementation NSArray (NSKeyValueObserving) -- (void)addObserver:(id)observer - forKeyPath:(NSString *)keyPath - options:(NSKeyValueObservingOptions)options - context:(void *)context +- (void)addObserver: (id)observer + forKeyPath: (NSString *)keyPath + options: (NSKeyValueObservingOptions)options + context: (void *)context { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } -- (void)removeObserver:(id)observer - forKeyPath:(NSString *)keyPath - context:(void *)context +- (void)removeObserver: (id)observer + forKeyPath: (NSString *)keyPath + context: (void *)context { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } -- (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath +- (void)removeObserver: (id)observer forKeyPath:(NSString *)keyPath { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } -- (void)addObserver:(id)observer - toObjectsAtIndexes:(NSIndexSet *)indexes - forKeyPath:(NSString *)keyPath - options:(NSKeyValueObservingOptions)options - context:(void *)context +- (void)addObserver: (id)observer + toObjectsAtIndexes: (NSIndexSet *)indexes + forKeyPath: (NSString *)keyPath + options: (NSKeyValueObservingOptions)options + context: (void *)context { [indexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { [[self objectAtIndex:index] addObserver:observer @@ -1163,10 +1200,10 @@ - (void)addObserver:(id)observer }]; } -- (void)removeObserver:(id)observer - fromObjectsAtIndexes:(NSIndexSet *)indexes - forKeyPath:(NSString *)keyPath - context:(void *)context +- (void)removeObserver: (id)observer + fromObjectsAtIndexes: (NSIndexSet *)indexes + forKeyPath: (NSString *)keyPath + context: (void *)context { [indexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { [[self objectAtIndex:index] removeObserver:observer @@ -1175,9 +1212,9 @@ - (void)removeObserver:(id)observer }]; } -- (void)removeObserver:(NSObject *)observer - fromObjectsAtIndexes:(NSIndexSet *)indexes - forKeyPath:(NSString *)keyPath +- (void)removeObserver: (NSObject *)observer + fromObjectsAtIndexes: (NSIndexSet *)indexes + forKeyPath: (NSString *)keyPath { [self removeObserver:observer fromObjectsAtIndexes:indexes @@ -1194,22 +1231,22 @@ - (void)removeObserver:(NSObject *)observer @implementation NSSet (NSKeyValueObserving) -- (void)addObserver:(id)observer - forKeyPath:(NSString *)keyPath - options:(NSKeyValueObservingOptions)options - context:(void *)context +- (void)addObserver: (id)observer + forKeyPath: (NSString *)keyPath + options: (NSKeyValueObservingOptions)options + context: (void *)context { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } -- (void)removeObserver:(id)observer - forKeyPath:(NSString *)keyPath - context:(void *)context +- (void)removeObserver: (id)observer + forKeyPath: (NSString *)keyPath + context: (void *)context { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } -- (void)removeObserver:(id)observer forKeyPath:(NSString *)keyPath +- (void)removeObserver: (id)observer forKeyPath:(NSString *)keyPath { NS_COLLECTION_THROW_ILLEGAL_KVO(keyPath); } diff --git a/Source/NSKVOSwizzling.m b/Source/NSKVOSwizzling.m index 9e62bc7f1..5b9965baa 100644 --- a/Source/NSKVOSwizzling.m +++ b/Source/NSKVOSwizzling.m @@ -111,12 +111,11 @@ the KVO machinery (if implemented using manual subclassing) would delete all */ object_addMethod_np(object, @selector(setObject:forKey:), - (IMP) (NSKVO$setObject$forKey$), "v@:@@"); + (IMP)(NSKVO$setObject$forKey$), "v@:@@"); object_addMethod_np(object, @selector(removeObjectForKey:), - (IMP) (NSKVO$removeObjectForKey$), "v@:@"); - - object_addMethod_np(object, @selector(_isKVOAware), (IMP) (NSKVO$nilIMP), - "v@:"); + (IMP)(NSKVO$removeObjectForKey$), "v@:@"); + object_addMethod_np(object, @selector(_isKVOAware), + (IMP)(NSKVO$nilIMP), "v@:"); } #pragma region Method Implementations @@ -144,12 +143,12 @@ the KVO machinery (if implemented using manual subclassing) would delete all if (!selMappings) { selMappings = [NSMapTable - mapTableWithKeyOptions:NSPointerFunctionsOpaqueMemory - | NSPointerFunctionsOpaquePersonality - valueOptions:NSPointerFunctionsStrongMemory | - NSPointerFunctionsObjectPersonality]; + mapTableWithKeyOptions: NSPointerFunctionsOpaqueMemory + | NSPointerFunctionsOpaquePersonality + valueOptions: NSPointerFunctionsStrongMemory + | NSPointerFunctionsObjectPersonality]; objc_setAssociatedObject(cls, &s_selMapKey, (id) selMappings, - OBJC_ASSOCIATION_RETAIN); + OBJC_ASSOCIATION_RETAIN); } return selMappings; } @@ -159,21 +158,22 @@ the KVO machinery (if implemented using manual subclassing) would delete all _keyForSelector(id object, SEL selector) { return (NSString *) NSMapGet(_selectorMappingsForObject(object), - sel_getName(selector)); + sel_getName(selector)); } static inline void _associateSelectorWithKey(id object, SEL selector, NSString *key) { - // this must be insertIfAbsent. otherwise, when calling a setter that itself - // causes observers to be added/removed on this key, this would call this - // method and overwrite the association selector->key with an identical key - // but another object. unfortunately, this would mean that the - // notifyingSetImpl below would then have a dead ```key``` pointer once it - // came time to call didChangeValueForKey (because apparently ARC doesn't take - // care of this properly) - NSMapInsertIfAbsent(_selectorMappingsForObject(object), sel_getName(selector), - key); + /* this must be insertIfAbsent. otherwise, when calling a setter that itself + * causes observers to be added/removed on this key, this would call this + * method and overwrite the association selector->key with an identical key + * but another object. unfortunately, this would mean that the + * notifyingSetImpl below would then have a dead ```key``` pointer once it + * came time to call didChangeValueForKey (because apparently ARC doesn't take + * care of this properly) + */ + NSMapInsertIfAbsent(_selectorMappingsForObject(object), + sel_getName(selector), key); } static void @@ -181,17 +181,19 @@ the KVO machinery (if implemented using manual subclassing) would delete all { NSString *key = _keyForSelector(self, _cmd); - // [Source: NSInvocation.mm] - // This attempts to flatten the method's arguments (as determined by its type - // encoding) from the stack into a buffer. That buffer is then emitted back - // onto the stack for the imp callthrough. This only works if we assume that - // our calling convention passes variadics and non-variadics in the same way: - // on the stack. For our two supported platforms, this seems to hold true. - NSMethodSignature *sig = [self methodSignatureForSelector:_cmd]; - size_t argSz = objc_sizeof_type([sig getArgumentTypeAtIndex:2]); + /* [Source: NSInvocation.mm] + * This attempts to flatten the method's arguments (as determined by its type + * encoding) from the stack into a buffer. That buffer is then emitted back + * onto the stack for the imp callthrough. This only works if we assume that + * our calling convention passes variadics and non-variadics in the same way: + * on the stack. For our two supported platforms, this seems to hold true. + */ + NSMethodSignature *sig = [self methodSignatureForSelector: _cmd]; + size_t argSz = objc_sizeof_type([sig getArgumentTypeAtIndex: 2]); size_t nStackArgs = argSz / sizeof(uintptr_t); uintptr_t *raw = (uintptr_t *) (calloc(sizeof(uintptr_t), nStackArgs)); - va_list ap; + va_list ap; + va_start(ap, _cmd); for (uintptr_t i = 0; i < nStackArgs; ++i) { @@ -199,40 +201,40 @@ the KVO machinery (if implemented using manual subclassing) would delete all } va_end(ap); - [self willChangeValueForKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - IMP imp = (id(*)(id, SEL, ...)) objc_msg_lookup_super(&super, _cmd); - - // VSO 5955259; NSInvocation informs this implementation and this will need - // to be cleaned up when NSInvocation is. - switch (nStackArgs) - { - case 1: - imp(self, _cmd, raw[0]); - break; - case 2: - imp(self, _cmd, raw[0], raw[1]); - break; - case 3: - imp(self, _cmd, raw[0], raw[1], raw[2]); - break; - case 4: - imp(self, _cmd, raw[0], raw[1], raw[2], raw[3]); - break; - case 5: - imp(self, _cmd, raw[0], raw[1], raw[2], raw[3], raw[4]); - break; - case 6: - imp(self, _cmd, raw[0], raw[1], raw[2], raw[3], raw[4], raw[5]); - break; - default: - NSLog(@"Can't override setter with more than 6 sizeof(long int) stack " - @"arguments."); - return; - } + [self willChangeValueForKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + IMP imp = (id(*)(id, SEL, ...)) objc_msg_lookup_super(&super, _cmd); - [self didChangeValueForKey:key]; + // VSO 5955259; NSInvocation informs this implementation and this will need + // to be cleaned up when NSInvocation is. + switch (nStackArgs) + { + case 1: + imp(self, _cmd, raw[0]); + break; + case 2: + imp(self, _cmd, raw[0], raw[1]); + break; + case 3: + imp(self, _cmd, raw[0], raw[1], raw[2]); + break; + case 4: + imp(self, _cmd, raw[0], raw[1], raw[2], raw[3]); + break; + case 5: + imp(self, _cmd, raw[0], raw[1], raw[2], raw[3], raw[4]); + break; + case 6: + imp(self, _cmd, raw[0], raw[1], raw[2], raw[3], raw[4], raw[5]); + break; + default: + NSLog(@"Can't override setter with more than 6" + @" sizeof(long int) stack arguments."); + return; + } + } + [self didChangeValueForKey: key]; free(raw); } @@ -248,55 +250,63 @@ the KVO machinery (if implemented using manual subclassing) would delete all static void NSKVONotifying$insertObject$inXxxAtIndex$(id self, SEL _cmd, id object, - NSUInteger index) + NSUInteger index) { NSString *key = _keyForSelector(self, _cmd); - NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:index]; - - [self willChange:NSKeyValueChangeInsertion - valuesAtIndexes:indexes - forKey:key]; + NSIndexSet *indexes = [NSIndexSet indexSetWithIndex: index]; - struct objc_super super = {self, ABI_SUPER(self)}; - insertObjectAtIndexIMP imp - = (void (*)(id, SEL, id, NSUInteger)) objc_msg_lookup_super(&super, _cmd); - imp(self, _cmd, object, index); - - [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:key]; + [self willChange: NSKeyValueChangeInsertion + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + insertObjectAtIndexIMP imp = (void (*)(id, SEL, id, NSUInteger)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, object, index); + } + [self didChange: NSKeyValueChangeInsertion + valuesAtIndexes: indexes + forKey: key]; } static void NSKVONotifying$insertXxx$atIndexes$(id self, SEL _cmd, id object, - NSIndexSet *indexes) + NSIndexSet *indexes) { NSString *key = _keyForSelector(self, _cmd); - [self willChange:NSKeyValueChangeInsertion - valuesAtIndexes:indexes - forKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - insertAtIndexesIMP imp - = (void (*)(id, SEL, id, NSIndexSet *)) objc_msg_lookup_super(&super, _cmd); - imp(self, _cmd, object, indexes); - - [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:key]; + [self willChange: NSKeyValueChangeInsertion + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + insertAtIndexesIMP imp = (void (*)(id, SEL, id, NSIndexSet *)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, object, indexes); + } + [self didChange: NSKeyValueChangeInsertion + valuesAtIndexes: indexes + forKey: key]; } static void NSKVONotifying$removeObjectFromXxxAtIndex$(id self, SEL _cmd, NSUInteger index) { NSString *key = _keyForSelector(self, _cmd); - NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:index]; - - [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - removeObjectAtIndexIMP imp - = (void (*)(id, SEL, NSUInteger)) objc_msg_lookup_super(&super, _cmd); - imp(self, _cmd, index); + NSIndexSet *indexes = [NSIndexSet indexSetWithIndex: index]; - [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:key]; + [self willChange: NSKeyValueChangeRemoval + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + removeObjectAtIndexIMP imp = (void (*)(id, SEL, NSUInteger)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, index); + } + [self didChange: NSKeyValueChangeRemoval + valuesAtIndexes: indexes + forKey: key]; } static void @@ -304,116 +314,127 @@ the KVO machinery (if implemented using manual subclassing) would delete all { NSString *key = _keyForSelector(self, _cmd); - [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - removeAtIndexesIMP imp - = (void (*)(id, SEL, NSIndexSet *)) objc_msg_lookup_super(&super, _cmd); - imp(self, _cmd, indexes); - - [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:key]; + [self willChange: NSKeyValueChangeRemoval + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + removeAtIndexesIMP imp = (void (*)(id, SEL, NSIndexSet *)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, indexes); + } + [self didChange: NSKeyValueChangeRemoval + valuesAtIndexes: indexes + forKey: key]; } static void NSKVONotifying$replaceObjectInXxxAtIndex$withObject$(id self, SEL _cmd, - NSUInteger index, - id object) + NSUInteger index, id object) { NSString *key = _keyForSelector(self, _cmd); - NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:index]; + NSIndexSet *indexes = [NSIndexSet indexSetWithIndex: index]; - [self willChange:NSKeyValueChangeReplacement - valuesAtIndexes:indexes - forKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - replaceObjectAtIndexWithObjectIMP imp - = (void (*)(id, SEL, NSUInteger, id)) objc_msg_lookup_super(&super, _cmd); - imp(self, _cmd, index, object); - - [self didChange:NSKeyValueChangeReplacement - valuesAtIndexes:indexes - forKey:key]; + [self willChange: NSKeyValueChangeReplacement + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + replaceObjectAtIndexWithObjectIMP imp = (void (*)(id, SEL, NSUInteger, id)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, index, object); + } + [self didChange: NSKeyValueChangeReplacement + valuesAtIndexes: indexes + forKey: key]; } static void NSKVONotifying$replaceXxxAtIndexes$withXxx$(id self, SEL _cmd, - NSIndexSet *indexes, - NSArray *objects) + NSIndexSet *indexes, NSArray *objects) { NSString *key = _keyForSelector(self, _cmd); - [self willChange:NSKeyValueChangeReplacement - valuesAtIndexes:indexes - forKey:key]; - - struct objc_super super = {self, ABI_SUPER(self)}; - replaceAtIndexesIMP imp - = (void (*)(id, SEL, NSIndexSet *, NSArray *)) objc_msg_lookup_super(&super, - _cmd); - imp(self, _cmd, indexes, objects); - - [self didChange:NSKeyValueChangeReplacement - valuesAtIndexes:indexes - forKey:key]; + [self willChange: NSKeyValueChangeReplacement + valuesAtIndexes: indexes + forKey: key]; + { + struct objc_super super = {self, ABI_SUPER(self)}; + replaceAtIndexesIMP imp = (void (*)(id, SEL, NSIndexSet *, NSArray *)) + objc_msg_lookup_super(&super, _cmd); + imp(self, _cmd, indexes, objects); + } + [self didChange: NSKeyValueChangeReplacement + valuesAtIndexes: indexes + forKey: key]; } #define GENERATE_NSKVOSetDispatch_IMPL(Kind) \ static inline void _NSKVOSetDispatch_##Kind(id self, SEL _cmd, NSSet *set) \ { \ NSString *key = _keyForSelector(self, _cmd); \ - [self willChangeValueForKey:key withSetMutation:Kind usingObjects:set]; \ + [self willChangeValueForKey: key withSetMutation: Kind usingObjects: set]; \ + { \ struct objc_super super = {self, ABI_SUPER(self)}; \ void (*imp)(id, SEL, NSSet *) \ = (void (*)(id, SEL, NSSet *)) objc_msg_lookup_super(&super, _cmd); \ imp(self, _cmd, set); \ - [self didChangeValueForKey:key withSetMutation:Kind usingObjects:set]; \ + } \ + [self didChangeValueForKey: key withSetMutation: Kind usingObjects: set]; \ } #define GENERATE_NSKVOSetDispatchIndividual_IMPL(Kind) \ static inline void _NSKVOSetDispatchIndividual_##Kind(id self, SEL _cmd, \ - id obj) \ + id obj) \ { \ - NSSet *set = [NSSet setWithObject:obj]; \ + NSSet *set = [NSSet setWithObject: obj]; \ NSString *key = _keyForSelector(self, _cmd); \ - [self willChangeValueForKey:key withSetMutation:Kind usingObjects:set]; \ + [self willChangeValueForKey: key withSetMutation: Kind usingObjects: set]; \ + { \ struct objc_super super = {self, ABI_SUPER(self)}; \ void (*imp)(id, SEL, id) \ = (void (*)(id, SEL, id)) objc_msg_lookup_super(&super, _cmd); \ imp(self, _cmd, obj); \ - [self didChangeValueForKey:key withSetMutation:Kind usingObjects:set]; \ + } \ + [self didChangeValueForKey: key withSetMutation: Kind usingObjects: set]; \ } GENERATE_NSKVOSetDispatchIndividual_IMPL(NSKeyValueUnionSetMutation); GENERATE_NSKVOSetDispatchIndividual_IMPL(NSKeyValueMinusSetMutation); -GENERATE_NSKVOSetDispatchIndividual_IMPL(NSKeyValueIntersectSetMutation); +//GENERATE_NSKVOSetDispatchIndividual_IMPL(NSKeyValueIntersectSetMutation); GENERATE_NSKVOSetDispatch_IMPL(NSKeyValueUnionSetMutation); GENERATE_NSKVOSetDispatch_IMPL(NSKeyValueMinusSetMutation); GENERATE_NSKVOSetDispatch_IMPL(NSKeyValueIntersectSetMutation); -// - (void)setObject:(id)object forKey:(NSString*)key +// - (void)setObject: (id)object forKey: (NSString*)key static void NSKVO$setObject$forKey$(id self, SEL _cmd, id object, NSString *key) { - [self willChangeValueForKey:key]; + [self willChangeValueForKey: key]; +{ struct objc_super super = {self, ABI_SUPER(self)}; - setObjectForKeyIMP imp - = (void (*)(id, SEL, id, NSString *)) objc_msg_lookup_super(&super, _cmd); + setObjectForKeyIMP imp; + + imp = (void (*)(id, SEL, id, NSString *)) objc_msg_lookup_super(&super, _cmd); imp(self, _cmd, object, key); - [self didChangeValueForKey:key]; +} + [self didChangeValueForKey: key]; } -// - (void)removeObjectForKey:(NSString*)key +// - (void)removeObjectForKey: (NSString*)key static void NSKVO$removeObjectForKey$(id self, SEL _cmd, NSString *key) { - [self willChangeValueForKey:key]; + [self willChangeValueForKey: key]; +{ struct objc_super super = {self, ABI_SUPER(self)}; - removeObjectForKeyIMP imp - = (void (*)(id, SEL, NSString *)) objc_msg_lookup_super(&super, _cmd); + removeObjectForKeyIMP imp; + + imp = (void (*)(id, SEL, NSString *)) objc_msg_lookup_super(&super, _cmd); imp(self, _cmd, key); - [self didChangeValueForKey:key]; +} + [self didChangeValueForKey: key]; } #pragma endregion @@ -424,9 +445,9 @@ static void funcName(id self, SEL _cmd, type val) \ NSString *key = _keyForSelector(self, _cmd); \ void (*imp)(id, SEL, type) \ = (void (*)(id, SEL, type)) objc_msg_lookup_super(&super, _cmd); \ - [self willChangeValueForKey:key]; \ + [self willChangeValueForKey: key]; \ imp(self, _cmd, val); \ - [self didChangeValueForKey:key]; \ + [self didChangeValueForKey: key]; \ } GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplDouble, double); @@ -443,9 +464,9 @@ static void funcName(id self, SEL _cmd, type val) \ GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplUnsignedShort, unsigned short); GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplUnsignedLong, unsigned long); GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplUnsignedLongLong, - unsigned long long); + unsigned long long); -GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplBool, bool); +// GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplBool, bool); GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplObject, id); GENERATE_NOTIFYING_SET_IMPL(notifyingSetImplPointer, void *); @@ -473,7 +494,7 @@ static void funcName(id self, SEL _cmd, type val) \ buf[3 + len] = ':'; buf[3 + len + 1] = '\0'; sel = sel_getUid(buf); - if ([self respondsToSelector:sel]) + if ([self respondsToSelector: sel]) { return sel; } @@ -485,19 +506,23 @@ static void funcName(id self, SEL _cmd, type val) \ static inline void _NSKVOEnsureSimpleKeyWillNotify(id object, NSString *key, const char *rawKey) { - SEL sel = KVCSetterForPropertyName(object, rawKey); - - Method originalMethod = class_getInstanceMethod(object_getClass(object), sel); - const char *types = method_getTypeEncoding(originalMethod); + Method originalMethod; + const char *valueType; + const char *types; + NSMethodSignature *sig; + SEL sel; + IMP newImpl = NULL; + + sel = KVCSetterForPropertyName(object, rawKey); + originalMethod = class_getInstanceMethod(object_getClass(object), sel); + types = method_getTypeEncoding(originalMethod); if (!types) { return; } - NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types]; - - const char *valueType = [sig getArgumentTypeAtIndex:2]; - IMP newImpl = NULL; + sig = [NSMethodSignature signatureWithObjCTypes: types]; + valueType = [sig getArgumentTypeAtIndex: 2]; switch (valueType[0]) { @@ -507,19 +532,19 @@ static void funcName(id self, SEL _cmd, type val) \ size_t valueSize = objc_sizeof_type(valueType); if (valueSize > 6 * sizeof(uintptr_t)) { - [NSException raise:NSInvalidArgumentException - format:@"Class %s key %@ has a value size of %u bytes, " - @"and cannot currently be KVO compliant.", - class_getName(object_getClass(object)), key, - (unsigned int) (valueSize)]; + [NSException raise: NSInvalidArgumentException + format: @"Class %s key %@ has a value size of %u bytes" + @", and cannot currently be KVO compliant.", + class_getName(object_getClass(object)), key, + (unsigned int) (valueSize)]; } newImpl = (IMP) (¬ifyingVariadicSetImpl); break; } default: - [NSException raise:NSInvalidArgumentException - format:@"Class %s is not KVO compliant for key %@.", - class_getName(object_getClass(object)), key]; + [NSException raise: NSInvalidArgumentException + format: @"Class %s is not KVO compliant for key %@.", + class_getName(object_getClass(object)), key]; return; } @@ -530,15 +555,15 @@ static void funcName(id self, SEL _cmd, type val) \ static void replaceAndAssociateWithKey(id object, SEL sel, NSString *key, IMP imp) { - if ([object respondsToSelector:sel]) + if ([object respondsToSelector: sel]) { const char *selName = sel_getName(sel); Method method = class_getInstanceMethod(object_getClass(object), sel); if (!method) { NSWarnLog(@"NSObject (NSKeyValueObservation): Unable to find method " - @"for %s on class %s; perhaps it is a forward?", - selName, object_getClassName(object)); + @"for %s on class %s; perhaps it is a forward?", + selName, object_getClassName(object)); return; } @@ -550,11 +575,13 @@ static void funcName(id self, SEL _cmd, type val) \ static SEL formatSelector(NSString *format, ...) { - va_list ap; + NSString *s; + SEL sel; + va_list ap; + va_start(ap, format); - SEL sel - = NSSelectorFromString([[[NSString alloc] initWithFormat:format - arguments:ap] autorelease]); + s = [[NSString alloc] initWithFormat: format arguments: ap]; + sel = NSSelectorFromString([s autorelease]); va_end(ap); return sel; } @@ -562,73 +589,75 @@ static void funcName(id self, SEL _cmd, type val) \ // invariant: rawKey has already been capitalized static inline void _NSKVOEnsureOrderedCollectionWillNotify(id object, NSString *key, - const char *rawKey) + const char *rawKey) { SEL insertOne = formatSelector(@"insertObject:in%sAtIndex:", rawKey); SEL insertMany = formatSelector(@"insert%s:atIndexes:", rawKey); - if ([object respondsToSelector:insertOne] || - [object respondsToSelector:insertMany]) + + if ([object respondsToSelector: insertOne] + || [object respondsToSelector: insertMany]) { replaceAndAssociateWithKey(object, insertOne, key, - (IMP) - NSKVONotifying$insertObject$inXxxAtIndex$); + (IMP)NSKVONotifying$insertObject$inXxxAtIndex$); replaceAndAssociateWithKey(object, insertMany, key, - (IMP) NSKVONotifying$insertXxx$atIndexes$); + (IMP)NSKVONotifying$insertXxx$atIndexes$); replaceAndAssociateWithKey( object, formatSelector(@"removeObjectFrom%sAtIndex:", rawKey), key, - (IMP) NSKVONotifying$removeObjectFromXxxAtIndex$); + (IMP)NSKVONotifying$removeObjectFromXxxAtIndex$); replaceAndAssociateWithKey(object, - formatSelector(@"remove%sAtIndexes:", rawKey), - key, (IMP) NSKVONotifying$removeXxxAtIndexes$); + formatSelector(@"remove%sAtIndexes:", rawKey), + key, (IMP)NSKVONotifying$removeXxxAtIndexes$); replaceAndAssociateWithKey( object, formatSelector(@"replaceObjectIn%sAtIndex:withObject:", rawKey), - key, (IMP) NSKVONotifying$replaceObjectInXxxAtIndex$withObject$); + key, (IMP)NSKVONotifying$replaceObjectInXxxAtIndex$withObject$); replaceAndAssociateWithKey( object, formatSelector(@"replace%sAtIndexes:with%s:", rawKey, rawKey), - key, (IMP) NSKVONotifying$replaceXxxAtIndexes$withXxx$); + key, (IMP)NSKVONotifying$replaceXxxAtIndexes$withXxx$); } } // invariant: rawKey has already been capitalized static inline void _NSKVOEnsureUnorderedCollectionWillNotify(id object, NSString *key, - const char *rawKey) + const char *rawKey) { SEL addOne = formatSelector(@"add%sObject:", rawKey); SEL addMany = formatSelector(@"add%s:", rawKey); SEL removeOne = formatSelector(@"remove%sObject:", rawKey); SEL removeMany = formatSelector(@"remove%s:", rawKey); - if (([object respondsToSelector:addOne] || - [object respondsToSelector:addMany]) - && ([object respondsToSelector:removeOne] || - [object respondsToSelector:removeMany])) + + if (([object respondsToSelector: addOne] + || [object respondsToSelector: addMany]) + && ([object respondsToSelector: removeOne] + || [object respondsToSelector: removeMany])) { replaceAndAssociateWithKey( object, addOne, key, - (IMP) _NSKVOSetDispatchIndividual_NSKeyValueUnionSetMutation); + (IMP)_NSKVOSetDispatchIndividual_NSKeyValueUnionSetMutation); replaceAndAssociateWithKey( object, addMany, key, - (IMP) _NSKVOSetDispatch_NSKeyValueUnionSetMutation); + (IMP)_NSKVOSetDispatch_NSKeyValueUnionSetMutation); replaceAndAssociateWithKey( object, removeOne, key, - (IMP) _NSKVOSetDispatchIndividual_NSKeyValueMinusSetMutation); + (IMP)_NSKVOSetDispatchIndividual_NSKeyValueMinusSetMutation); replaceAndAssociateWithKey( object, removeMany, key, - (IMP) _NSKVOSetDispatch_NSKeyValueMinusSetMutation); + (IMP)_NSKVOSetDispatch_NSKeyValueMinusSetMutation); replaceAndAssociateWithKey( object, formatSelector(@"intersect%s:", rawKey), key, - (IMP) _NSKVOSetDispatch_NSKeyValueIntersectSetMutation); + (IMP)_NSKVOSetDispatch_NSKeyValueIntersectSetMutation); } } char * mutableBufferFromString(NSString *string) { - NSUInteger lengthInBytes = [string length] + 1; - char *rawKey = (char *) malloc(lengthInBytes); - [string getCString:rawKey - maxLength:lengthInBytes - encoding:NSASCIIStringEncoding]; + NSUInteger lengthInBytes = [string length] + 1; + char *rawKey = (char *) malloc(lengthInBytes); + + [string getCString: rawKey + maxLength: lengthInBytes + encoding: NSASCIIStringEncoding]; return rawKey; } @@ -636,6 +665,8 @@ static void funcName(id self, SEL _cmd, type val) \ void _NSKVOEnsureKeyWillNotify(id object, NSString *key) { + char *rawKey; + // Since we cannot replace the isa of tagged pointer objects, we can't swizzle // them. if (isSmallObject_np(object)) @@ -644,12 +675,12 @@ static void funcName(id self, SEL _cmd, type val) \ } // A class is allowed to decline automatic swizzling for any/all of its keys. - if (![[object class] automaticallyNotifiesObserversForKey:key]) + if (![[object class] automaticallyNotifiesObserversForKey: key]) { return; } - char *rawKey = mutableBufferFromString(key); + rawKey = mutableBufferFromString(key); rawKey[0] = toupper(rawKey[0]); @synchronized(object) diff --git a/Source/NSUserDefaults.m b/Source/NSUserDefaults.m index 847885199..737030780 100644 --- a/Source/NSUserDefaults.m +++ b/Source/NSUserDefaults.m @@ -362,15 +362,15 @@ - (BOOL) synchronize; NSMutableArray *names = [NSMutableArray arrayWithCapacity: 10]; #if defined(_WIN32) - NSEnumerator *enumerator; - NSArray *languages; - NSString *locale; - BOOL ret; - + NSEnumerator *enumerator; + NSArray *languages; + NSString *locale; + BOOL ret; unsigned long numberOfLanguages = 0; unsigned long length = 7; unsigned long factor = sizeof(wchar_t); - wchar_t *buffer = malloc(length * factor); + wchar_t *buffer = malloc(length * factor); + if (!buffer) { return names; @@ -380,56 +380,61 @@ - (BOOL) synchronize; * two-letter language code, and CC is the two-letter country code. */ ret = GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numberOfLanguages, - buffer, &length); + buffer, &length); if (!ret) { length = 0; - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && - GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numberOfLanguages, - NULL, &length)) { - wchar_t *oldBuffer = buffer; - buffer = realloc(buffer, length * factor); - if (!buffer) - { - free(oldBuffer); - return names; - } + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER + && GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numberOfLanguages, + NULL, &length)) + { + wchar_t *oldBuffer = buffer; - ret = GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numberOfLanguages, buffer, &length); - if (!ret) - { - free(buffer); - return names; - } - } + buffer = realloc(buffer, length * factor); + if (!buffer) + { + free(oldBuffer); + return names; + } + + ret = GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, + &numberOfLanguages, buffer, &length); + if (!ret) + { + free(buffer); + return names; + } + } } - languages = [NSString arrayFromWCharList:buffer length:length]; + languages = [NSString arrayFromWCharList: buffer length: length]; enumerator = [languages objectEnumerator]; free(buffer); - while (nil != (locale = [enumerator nextObject])) - { + while (nil != (locale = [enumerator nextObject])) + { /* Replace "-" Separator with "_" */ - locale = [locale stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; - [names addObjectsFromArray: GSLanguagesFromLocale(locale)]; - } + locale = [locale stringByReplacingOccurrencesOfString: @"-" + withString: @"_"]; + [names addObjectsFromArray: GSLanguagesFromLocale(locale)]; + } #elif defined(__ANDROID__) - // When running on Android, the process must be correctly initialized - // with GSInitializeProcessAndroid (See NSProcessInfo). - // - // If the minimum API level is 24 or higher, the user-prefered locales - // are retrieved from the Android system and passed as GSAndroidLocaleList - // process argument - NSArray *args = [[NSProcessInfo processInfo] arguments]; - NSEnumerator *enumerator = [args objectEnumerator]; - NSString *key = nil; - NSString *localeList = nil; + /* When running on Android, the process must be correctly initialized + * with GSInitializeProcessAndroid (See NSProcessInfo). + * + * If the minimum API level is 24 or higher, the user-prefered locales + * are retrieved from the Android system and passed as GSAndroidLocaleList + * process argument + */ + NSArray *args = [[NSProcessInfo processInfo] arguments]; + NSEnumerator *enumerator = [args objectEnumerator]; + NSString *key = nil; + NSString *localeList = nil; [enumerator nextObject]; // Skip process name. while (nil != (key = [enumerator nextObject])) { - if ([key isEqualToString:@"-GSAndroidLocaleList"]) + if ([key isEqualToString: @"-GSAndroidLocaleList"]) { localeList = [enumerator nextObject]; break; @@ -439,8 +444,8 @@ - (BOOL) synchronize; // The locale list is a comma-separated list of locales of form ll-CC if (localeList != nil) { - NSString *locale; - NSArray *locales = [localeList componentsSeparatedByString: @","]; + NSString *locale; + NSArray *locales = [localeList componentsSeparatedByString: @","]; enumerator = [locales objectEnumerator]; while (nil != (locale = [enumerator nextObject])) @@ -449,16 +454,19 @@ - (BOOL) synchronize; } } #else - // Add the languages listed in the LANGUAGE environment variable - // (a non-POSIX GNU extension) + /* Add the languages listed in the LANGUAGE environment variable + * (a non-POSIX GNU extension) + */ { - NSString *env = [[[NSProcessInfo processInfo] environment] - objectForKey: @"LANGUAGE"]; + NSString *env; + + env = [[[NSProcessInfo processInfo] environment] objectForKey: @"LANGUAGE"]; if (env != nil && [env length] > 0) { - NSArray *array = [env componentsSeparatedByString: @":"]; - NSEnumerator *enumerator = [array objectEnumerator]; - NSString *locale; + NSArray *array = [env componentsSeparatedByString: @":"]; + NSEnumerator *enumerator = [array objectEnumerator]; + NSString *locale; + while (nil != (locale = [enumerator nextObject])) { [names addObjectsFromArray: GSLanguagesFromLocale(locale)]; @@ -666,8 +674,8 @@ + (void) atExit * change the value of a key (the value is equal to the old value). * * https://developer.apple.com/documentation/foundation/nsuserdefaults#2926902 - * "You can use key-value observing to be notified of any updates to a particular - * default value. You can also register as an observer for + * "You can use key-value observing to be notified of any updates to + * a particular default value. You can also register as an observer for * NSUserDefaultsDidChangeNotification on the defaultCenter notification center * in order to be notified of all updates to a local defaults database." */ @@ -1514,30 +1522,36 @@ - (void) removeObjectForKey: (NSString*)defaultName NS_DURING { GSPersistentDomain *pd = [_persDomains objectForKey: processName]; - id old = [self objectForKey: defaultName]; + id old = [self objectForKey: defaultName]; if (nil != pd) { - if ([pd setObject: nil forKey: defaultName]) - { - id new; - [self _changePersistentDomain: processName]; - new = [self objectForKey: defaultName]; - // Emit only a KVO notification when the value has actually changed, - // meaning -objectForKey: would return a different value than before. - if ([new hash] != [old hash]) + if ([pd setObject: nil forKey: defaultName]) { - [self _notifyObserversOfChangeForKey: defaultName oldValue:old newValue: new]; + id new; + [self _changePersistentDomain: processName]; + new = [self objectForKey: defaultName]; + /* Emit only a KVO notification when the value has actually + * changed, meaning -objectForKey: would return a different + * value than before. + */ + if ([new hash] != [old hash]) + { + [self _notifyObserversOfChangeForKey: defaultName + oldValue: old + newValue: new]; + } } - } - else { - // We always notify observers of a change, even if the value - // itself is unchanged. - [[NSNotificationCenter defaultCenter] - postNotificationName: NSUserDefaultsDidChangeNotification - object: self]; + else + { + /* We always notify observers of a change, even if the value + * itself is unchanged. + */ + [[NSNotificationCenter defaultCenter] + postNotificationName: NSUserDefaultsDidChangeNotification + object: self]; - } + } } [_lock unlock]; } @@ -1672,25 +1686,29 @@ - (void) setObject: (id)value forKey: (NSString*)defaultName { id new; - // New value must be fetched from all domains, as there might be - // a registered default if value is nil, or the value is - // superseded by GSPrimary or NSArgumentDomain + /* New value must be fetched from all domains, as there might be + * a registered default if value is nil, or the value is + * superseded by GSPrimary or NSArgumentDomain + */ new = [self objectForKey: defaultName]; [self _changePersistentDomain: processName]; // Emit only a KVO notification when the value has actually changed if ([new hash] != [old hash]) { - [self _notifyObserversOfChangeForKey: defaultName oldValue:old newValue:new]; + [self _notifyObserversOfChangeForKey: defaultName + oldValue: old + newValue: new]; } } else { - // We always notify observers of a change, even if the value - // itself is unchanged. + /* We always notify observers of a change, even if the value + * itself is unchanged. + */ [[NSNotificationCenter defaultCenter] postNotificationName: NSUserDefaultsDidChangeNotification - object: self]; + object: self]; } [_lock unlock]; }