33 if (!
self._willChangeMessageCounter)
34 self._willChangeMessageCounter =
new Object();
36 if (!
self._willChangeMessageCounter[aKey])
37 self._willChangeMessageCounter[aKey] = 1;
39 self._willChangeMessageCounter[aKey] += 1;
50 if (
self._willChangeMessageCounter &&
self._willChangeMessageCounter[aKey])
52 self._willChangeMessageCounter[aKey] -= 1;
54 if (!
self._willChangeMessageCounter[aKey])
55 delete self._willChangeMessageCounter[aKey];
58 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
62 - (void)willChange:(CPKeyValueChange)aChange valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
69 if (!
self._willChangeMessageCounter)
70 self._willChangeMessageCounter =
new Object();
72 if (!
self._willChangeMessageCounter[aKey])
73 self._willChangeMessageCounter[aKey] = 1;
75 self._willChangeMessageCounter[aKey] += 1;
79 - (void)didChange:(CPKeyValueChange)aChange valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
86 if (
self._willChangeMessageCounter &&
self._willChangeMessageCounter[aKey])
88 self._willChangeMessageCounter[aKey] -= 1;
90 if (!
self._willChangeMessageCounter[aKey])
91 delete self._willChangeMessageCounter[aKey];
94 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
98 - (void)willChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)aMutationKind usingObjects:(CPSet)objects
105 if (!
self._willChangeMessageCounter)
106 self._willChangeMessageCounter =
new Object();
108 if (!
self._willChangeMessageCounter[aKey])
109 self._willChangeMessageCounter[aKey] = 1;
111 self._willChangeMessageCounter[aKey] += 1;
115 - (void)didChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)aMutationKind usingObjects:(CPSet)objects
119 if (
self._willChangeMessageCounter &&
self._willChangeMessageCounter[aKey])
121 self._willChangeMessageCounter[aKey] -= 1;
123 if (!
self._willChangeMessageCounter[aKey])
124 delete self._willChangeMessageCounter[aKey];
127 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
131 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aPath options:(CPKeyValueObservingOptions)options context:(
id)aContext
133 if (!anObserver || !aPath)
136 [[_CPKVOProxy proxyForObject:self] _addObserver:anObserver forKeyPath:aPath options:options context:aContext];
139 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aPath
141 if (!anObserver || !aPath)
144 [
self[KVOProxyKey] _removeObserver:anObserver forKeyPath:aPath];
157 + (BOOL)automaticallyNotifiesObserversForKey:(
CPString)aKey
159 var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1),
160 selector =
"automaticallyNotifiesObserversOf" + capitalizedKey,
161 aClass = [
self class];
163 if ([aClass respondsToSelector:selector])
164 return aClass.isa.objj_msgSend0(aClass, selector);
169 + (CPSet)keyPathsForValuesAffectingValueForKey:(
CPString)aKey
171 var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1),
172 selector =
"keyPathsForValuesAffecting" + capitalizedKey,
173 aClass = [
self class];
175 if ([aClass respondsToSelector:selector])
176 return aClass.isa.objj_msgSend0(aClass, selector);
183 var changeKind = [aChange
objectForKey:CPKeyValueChangeKindKey],
184 oldValue = [aChange
objectForKey:CPKeyValueChangeOldKey],
185 newValue = [aChange
objectForKey:CPKeyValueChangeNewKey];
187 if (newValue === [
CPNull null])
193 var indexes = [aChange
objectForKey:CPKeyValueChangeIndexesKey];
227 changeKind = [
self objectForKey:CPKeyValueChangeKindKey];
233 forKey:CPKeyValueChangeNewKey];
237 forKey:CPKeyValueChangeOldKey];
244 forKey:CPKeyValueChangeKindKey];
248 forKey:CPKeyValueChangeOldKey];
257 forKey:CPKeyValueChangeKindKey];
261 forKey:CPKeyValueChangeNewKey];
266 return inverseChangeDictionary;
297 _CPKeyValueChangeSetMutationObjectsKey =
@"_CPKeyValueChangeSetMutationObjectsKey";
298 _CPKeyValueChangeSetMutationKindKey =
@"_CPKeyValueChangeSetMutationKindKey";
299 _CPKeyValueChangeSetMutationNewValueKey =
@"_CPKeyValueChangeSetMutationNewValueKey";
301 var _changeKindForSetMutationKind =
function(mutationKind)
303 switch (mutationKind)
319 @implementation _CPKVOProxy :
CPObject 326 Object _observersForKey;
327 int _observersForKeyLength;
334 + (id)proxyForObject:(
CPObject)anObject
336 var proxy = anObject[KVOProxyKey];
341 return [[
self alloc] initWithTarget:anObject];
344 - (id)initWithTarget:(
id)aTarget
346 if (
self = [super
init])
348 _targetObject = aTarget;
349 _nativeClass = [aTarget class];
350 _observersForKey = {};
353 _minOptionsForKey = {};
354 _observersForKeyLength = 0;
356 [
self _replaceClass];
357 aTarget[KVOProxyKey] =
self;
362 - (void)_replaceClass
364 var currentClass = _nativeClass,
365 kvoClassName =
"$KVO_" + class_getName(_nativeClass),
366 existingKVOClass = objj_lookUpClass(kvoClassName);
368 if (existingKVOClass)
370 _targetObject.isa = existingKVOClass;
371 _replacedKeys = existingKVOClass._replacedKeys;
375 var kvoClass = objj_allocateClassPair(currentClass, kvoClassName);
377 objj_registerClassPair(kvoClass);
379 _replacedKeys = [CPSet set];
380 kvoClass._replacedKeys = _replacedKeys;
383 var methods = class_copyMethodList(_CPKVOModelSubclass);
386 methods = methods.concat(class_copyMethodList(_CPKVOModelDictionarySubclass));
388 class_addMethods(kvoClass, methods);
390 _targetObject.isa = kvoClass;
393 - (void)_replaceModifiersForKey:(
CPString)aKey
395 if ([_replacedKeys containsObject:aKey] || ![_nativeClass automaticallyNotifiesObserversForKey:aKey])
398 [_replacedKeys addObject:aKey];
400 var theClass = _nativeClass,
401 KVOClass = _targetObject.isa,
402 capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
405 var setKey_selector = sel_getUid(
"set" + capitalizedKey +
":"),
406 setKey_method = class_getInstanceMethod(theClass, setKey_selector);
410 var setKey_method_imp = setKey_method.method_imp;
412 class_addMethod(KVOClass, setKey_selector,
function(
self, _cmd, anObject)
414 [
self willChangeValueForKey:aKey];
416 setKey_method_imp(
self, _cmd, anObject);
418 [
self didChangeValueForKey:aKey];
419 }, setKey_method.method_types);
423 var _setKey_selector = sel_getUid(
"_set" + capitalizedKey +
":"),
424 _setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
428 var _setKey_method_imp = _setKey_method.method_imp;
430 class_addMethod(KVOClass, _setKey_selector,
function(
self, _cmd, anObject)
432 [
self willChangeValueForKey:aKey];
434 _setKey_method_imp(
self, _cmd, anObject);
436 [
self didChangeValueForKey:aKey];
437 }, _setKey_method.method_types);
441 var insertObject_inKeyAtIndex_selector = sel_getUid(
"insertObject:in" + capitalizedKey +
"AtIndex:"),
442 insertObject_inKeyAtIndex_method =
443 class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
445 insertKey_atIndexes_selector = sel_getUid(
"insert" + capitalizedKey +
":atIndexes:"),
446 insertKey_atIndexes_method =
447 class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
449 removeObjectFromKeyAtIndex_selector = sel_getUid(
"removeObjectFrom" + capitalizedKey +
"AtIndex:"),
450 removeObjectFromKeyAtIndex_method =
451 class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
453 removeKeyAtIndexes_selector = sel_getUid(
"remove" + capitalizedKey +
"AtIndexes:"),
454 removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
456 if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
457 (removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
459 if (insertObject_inKeyAtIndex_method)
461 var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
463 class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector,
function(
self, _cmd, anObject, anIndex)
465 [
self willChange:CPKeyValueChangeInsertion
469 insertObject_inKeyAtIndex_method_imp(
self, _cmd, anObject, anIndex);
471 [
self didChange:CPKeyValueChangeInsertion
474 }, insertObject_inKeyAtIndex_method.method_types);
477 if (insertKey_atIndexes_method)
479 var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
481 class_addMethod(KVOClass, insertKey_atIndexes_selector,
function(
self, _cmd, objects, indexes)
483 [
self willChange:CPKeyValueChangeInsertion
484 valuesAtIndexes:[indexes
copy]
487 insertKey_atIndexes_method_imp(
self, _cmd, objects, indexes);
489 [
self didChange:CPKeyValueChangeInsertion
490 valuesAtIndexes:[indexes
copy]
492 }, insertKey_atIndexes_method.method_types);
495 if (removeObjectFromKeyAtIndex_method)
497 var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
499 class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector,
function(
self, _cmd, anIndex)
501 [
self willChange:CPKeyValueChangeRemoval
505 removeObjectFromKeyAtIndex_method_imp(
self, _cmd, anIndex);
507 [
self didChange:CPKeyValueChangeRemoval
510 }, removeObjectFromKeyAtIndex_method.method_types);
513 if (removeKeyAtIndexes_method)
515 var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
517 class_addMethod(KVOClass, removeKeyAtIndexes_selector,
function(
self, _cmd, indexes)
519 [
self willChange:CPKeyValueChangeRemoval
520 valuesAtIndexes:[indexes
copy]
523 removeKeyAtIndexes_method_imp(
self, _cmd, indexes);
525 [
self didChange:CPKeyValueChangeRemoval
526 valuesAtIndexes:[indexes
copy]
528 }, removeKeyAtIndexes_method.method_types);
532 var replaceObjectInKeyAtIndex_withObject_selector =
533 sel_getUid(
"replaceObjectIn" + capitalizedKey +
"AtIndex:withObject:"),
534 replaceObjectInKeyAtIndex_withObject_method =
535 class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
537 if (replaceObjectInKeyAtIndex_withObject_method)
539 var replaceObjectInKeyAtIndex_withObject_method_imp =
540 replaceObjectInKeyAtIndex_withObject_method.method_imp;
542 class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
543 function(
self, _cmd, anIndex, anObject)
545 [
self willChange:CPKeyValueChangeReplacement
549 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, anIndex, anObject);
551 [
self didChange:CPKeyValueChangeReplacement
554 }, replaceObjectInKeyAtIndex_withObject_method.method_types);
557 var replaceKeyAtIndexes_withKey_selector =
558 sel_getUid(
"replace" + capitalizedKey +
"AtIndexes:with" + capitalizedKey +
":"),
559 replaceKeyAtIndexes_withKey_method =
560 class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
562 if (replaceKeyAtIndexes_withKey_method)
564 var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
566 class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector,
function(
self, _cmd, indexes, objects)
568 [
self willChange:CPKeyValueChangeReplacement
569 valuesAtIndexes:[indexes
copy]
572 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, indexes, objects);
574 [
self didChange:CPKeyValueChangeReplacement
575 valuesAtIndexes:[indexes
copy]
577 }, replaceKeyAtIndexes_withKey_method.method_types);
582 var addKeyObject_selector = sel_getUid(
"add" + capitalizedKey +
"Object:"),
583 addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
585 addKey_selector = sel_getUid(
"add" + capitalizedKey +
":"),
586 addKey_method = class_getInstanceMethod(theClass, addKey_selector),
588 removeKeyObject_selector = sel_getUid(
"remove" + capitalizedKey +
"Object:"),
589 removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
591 removeKey_selector = sel_getUid(
"remove" + capitalizedKey +
":"),
592 removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
594 if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
596 if (addKeyObject_method)
598 var addKeyObject_method_imp = addKeyObject_method.method_imp;
600 class_addMethod(KVOClass, addKeyObject_selector,
function(
self, _cmd, anObject)
602 [
self willChangeValueForKey:aKey
603 withSetMutation:CPKeyValueUnionSetMutation
604 usingObjects:[CPSet setWithObject:anObject]];
606 addKeyObject_method_imp(
self, _cmd, anObject);
608 [
self didChangeValueForKey:aKey
609 withSetMutation:CPKeyValueUnionSetMutation
610 usingObjects:[CPSet setWithObject:anObject]];
611 }, addKeyObject_method.method_types);
616 var addKey_method_imp = addKey_method.method_imp;
618 class_addMethod(KVOClass, addKey_selector,
function(
self, _cmd, objects)
620 [
self willChangeValueForKey:aKey
621 withSetMutation:CPKeyValueUnionSetMutation
622 usingObjects:[objects copy]];
624 addKey_method_imp(
self, _cmd, objects);
626 [
self didChangeValueForKey:aKey
627 withSetMutation:CPKeyValueUnionSetMutation
628 usingObjects:[objects copy]];
629 }, addKey_method.method_types);
632 if (removeKeyObject_method)
634 var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
636 class_addMethod(KVOClass, removeKeyObject_selector,
function(
self, _cmd, anObject)
638 [
self willChangeValueForKey:aKey
639 withSetMutation:CPKeyValueMinusSetMutation
640 usingObjects:[CPSet setWithObject:anObject]];
642 removeKeyObject_method_imp(
self, _cmd, anObject);
644 [
self didChangeValueForKey:aKey
645 withSetMutation:CPKeyValueMinusSetMutation
646 usingObjects:[CPSet setWithObject:anObject]];
647 }, removeKeyObject_method.method_types);
650 if (removeKey_method)
652 var removeKey_method_imp = removeKey_method.method_imp;
654 class_addMethod(KVOClass, removeKey_selector,
function(
self, _cmd, objects)
656 [
self willChangeValueForKey:aKey
657 withSetMutation:CPKeyValueMinusSetMutation
658 usingObjects:[objects copy]];
660 removeKey_method_imp(
self, _cmd, objects);
662 [
self didChangeValueForKey:aKey
663 withSetMutation:CPKeyValueMinusSetMutation
664 usingObjects:[objects copy]];
665 }, removeKey_method.method_types);
669 var intersectKey_selector = sel_getUid(
"intersect" + capitalizedKey +
":"),
670 intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
672 if (intersectKey_method)
674 var intersectKey_method_imp = intersectKey_method.method_imp;
676 class_addMethod(KVOClass, intersectKey_selector,
function(
self, _cmd, aSet)
678 [
self willChangeValueForKey:aKey
679 withSetMutation:CPKeyValueIntersectSetMutation
680 usingObjects:[aSet copy]];
682 intersectKey_method_imp(
self, _cmd, aSet);
684 [
self didChangeValueForKey:aKey
685 withSetMutation:CPKeyValueIntersectSetMutation
686 usingObjects:[aSet copy]];
687 }, intersectKey_method.method_types);
691 var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects],
692 affectingKeysCount = affectingKeys ? affectingKeys.length : 0;
694 if (!affectingKeysCount)
697 var dependentKeysForClass = _nativeClass[DependentKeysKey];
699 if (!dependentKeysForClass)
701 dependentKeysForClass = {};
702 _nativeClass[DependentKeysKey] = dependentKeysForClass;
705 while (affectingKeysCount--)
707 var affectingKey = affectingKeys[affectingKeysCount],
708 affectedKeys = dependentKeysForClass[affectingKey];
712 affectedKeys = [CPSet new];
713 dependentKeysForClass[affectingKey] = affectedKeys;
716 [affectedKeys addObject:aKey];
721 if (affectingKey.indexOf(
@".") !== -1)
724 [
self _replaceModifiersForKey:affectingKey];
728 - (void)observeValueForKeyPath:(
CPString)theKeyPath ofObject:(id)theObject change:(
CPDictionary)theChanges context:(id)theContext
731 var dependentKeysForClass = _nativeClass[DependentKeysKey],
732 dependantKeys = [dependentKeysForClass[theKeyPath] allObjects],
733 isBeforeFlag = !![theChanges objectForKey:CPKeyValueChangeNotificationIsPriorKey];
735 for (var i = 0; i < [dependantKeys count]; i++)
737 var dependantKey = [dependantKeys objectAtIndex:i];
738 [
self _sendNotificationsForKey:dependantKey changeOptions:theChanges isBefore:isBeforeFlag];
742 - (void)_addObserver:(
id)anObserver forKeyPath:(
CPString)aPath options:(CPKeyValueObservingOptions)options context:(id)aContext
749 if (aPath.indexOf(
'.') !==
CPNotFound && aPath.charAt(0) !==
'@')
750 forwarder = [[_CPKVOForwardingObserver alloc] initWithKeyPath:aPath
object:_targetObject observer:anObserver options:options context:aContext];
752 [
self _replaceModifiersForKey:aPath];
754 var observers = _observersForKey[aPath];
759 _observersForKey[aPath] = observers;
760 _observersForKeyLength++;
763 [observers setObject:_CPKVOInfoMake(anObserver, options, aContext, forwarder) forKey:[anObserver UID]];
771 var newValue = [_targetObject valueForKeyPath:aPath];
781 [anObserver observeValueForKeyPath:aPath ofObject:_targetObject change:changes context:aContext];
785 - (void)_removeObserver:(
id)anObserver forKeyPath:(
CPString)aPath
787 var observers = _observersForKey[aPath];
793 CPLog.warn(
@"Cannot remove an observer %@ for the key path \"%@\
" from %@ because it is not registered as an observer.", _targetObject, aPath, anObserver);
802 var observer = [observers objectForKey:[anObserver UID]],
803 forwarder = observer ? observer.forwarder : nil;
805 [forwarder finalize];
808 [observers removeObjectForKey:[anObserver UID]];
810 if (![observers count])
812 _observersForKeyLength--;
813 delete _observersForKey[aPath];
816 if (!_observersForKeyLength)
818 _targetObject.isa = _nativeClass;
819 delete _targetObject[KVOProxyKey];
825 - (void)_sendNotificationsForKey:(
CPString)aKey changeOptions:(
CPDictionary)changeOptions isBefore:(BOOL)isBefore
827 var changes = _changesForKey[aKey],
828 observers = [_observersForKey[aKey] allValues],
829 observersMinimumOptions = 0;
836 var level = _nestingForKey[aKey];
841 _nestingForKey[aKey] = level + 1;
846 _nestingForKey[aKey] = 1;
849 var count = observers ? observers.length : 0;
853 var observerInfo = observers[count];
855 observersMinimumOptions |= observerInfo.options &
kvoNewAndOld;
858 _minOptionsForKey[aKey] = observersMinimumOptions;
859 changes = changeOptions;
863 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
864 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
868 var setMutationObjects = [changes[_CPKeyValueChangeSetMutationObjectsKey] copy],
869 setExistingObjects = [[_targetObject valueForKey: aKey] copy];
873 [setExistingObjects intersectSet: setMutationObjects];
874 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
878 [setExistingObjects minusSet: setMutationObjects];
879 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
885 [setMutationObjects minusSet: setExistingObjects];
888 changes[_CPKeyValueChangeSetMutationNewValueKey] = setMutationObjects;
893 var type = [changes objectForKey:CPKeyValueChangeKindKey];
899 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
900 [changes setValue:newValues forKey:CPKeyValueChangeOldKey];
905 var oldValue = [_targetObject valueForKey:aKey];
907 if (oldValue === nil || oldValue === undefined)
910 [changes setObject:oldValue forKey:CPKeyValueChangeOldKey];
915 [changes setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey];
916 _changesForKey[aKey] = changes;
923 var level = _nestingForKey[aKey];
925 if (!changes || !level)
927 if (_targetObject._willChangeMessageCounter && _targetObject._willChangeMessageCounter[aKey])
930 _targetObject._willChangeMessageCounter[aKey] -= 1;
932 if (!_targetObject._willChangeMessageCounter[aKey])
933 delete _targetObject._willChangeMessageCounter[aKey];
938 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
941 _nestingForKey[aKey] = level - 1;
950 delete _nestingForKey[aKey];
952 [changes removeObjectForKey:CPKeyValueChangeNotificationIsPriorKey];
954 observersMinimumOptions = _minOptionsForKey[aKey];
958 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
959 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
965 var newValue = changes[_CPKeyValueChangeSetMutationNewValueKey];
966 [changes setValue:newValue forKey:CPKeyValueChangeNewKey];
969 delete changes[_CPKeyValueChangeSetMutationNewValueKey];
970 delete changes[_CPKeyValueChangeSetMutationObjectsKey];
971 delete changes[_CPKeyValueChangeSetMutationKindKey];
975 var type = [changes objectForKey:CPKeyValueChangeKindKey];
981 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
982 [changes setValue:newValues forKey:CPKeyValueChangeNewKey];
987 var newValue = [_targetObject valueForKey:aKey];
989 if (newValue === nil || newValue === undefined)
992 [changes setObject:newValue forKey:CPKeyValueChangeNewKey];
996 delete _minOptionsForKey[aKey];
997 delete _changesForKey[aKey];
1000 var count = observers ? observers.length : 0,
1005 var observerInfo = observers[count],
1006 options = observerInfo.options,
1008 observerChanges = nil;
1015 observerChanges = changes;
1022 observerChanges = changes;
1025 if (observerChanges)
1029 if (onlyNewAndOldOptions !== observersMinimumOptions)
1032 observerChanges = changesCache[onlyNewAndOldOptions];
1033 if (!observerChanges)
1036 changesCache[onlyNewAndOldOptions] = observerChanges = [changes mutableCopy];
1043 [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:observerChanges context:observerInfo.context];
1047 var dependentKeysMap = _nativeClass[DependentKeysKey];
1049 if (!dependentKeysMap)
1052 var dependentKeyPaths = [dependentKeysMap[aKey] allObjects];
1054 if (!dependentKeyPaths)
1058 count = [dependentKeyPaths count];
1060 for (; index < count; ++index)
1062 var keyPath = dependentKeyPaths[index];
1064 [
self _sendNotificationsForKey:keyPath
1065 changeOptions:isBefore ? [changeOptions copy] : _changesForKey[keyPath]
1071 @implementation _CPKVOModelSubclass :
CPObject 1076 - (void)willChangeValueForKey:(
CPString)aKey
1078 var superClass = [
self class],
1079 methodSelector =
@selector(willChangeValueForKey:),
1080 methodImp = class_getMethodImplementation(superClass, methodSelector);
1082 methodImp(
self, methodSelector, aKey);
1089 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1092 - (void)didChangeValueForKey:(
CPString)aKey
1094 var superClass = [
self class],
1095 methodSelector =
@selector(didChangeValueForKey:),
1096 methodImp = class_getMethodImplementation(superClass, methodSelector);
1098 methodImp(
self, methodSelector, aKey);
1103 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1106 - (void)willChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1108 var superClass = [
self class],
1109 methodSelector =
@selector(willChange:valuesAtIndexes:forKey:),
1110 methodImp = class_getMethodImplementation(superClass, methodSelector);
1112 methodImp(
self, methodSelector, change, indexes, aKey);
1119 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1122 - (void)didChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1124 var superClass = [
self class],
1125 methodSelector =
@selector(didChange:valuesAtIndexes:forKey:),
1126 methodImp = class_getMethodImplementation(superClass, methodSelector);
1128 methodImp(
self, methodSelector, change, indexes, aKey);
1133 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1136 - (void)willChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1138 var superClass = [
self class],
1139 methodSelector =
@selector(willChangeValueForKey:withSetMutation:usingObjects:),
1140 methodImp = class_getMethodImplementation(superClass, methodSelector);
1142 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1147 var changeKind = _changeKindForSetMutationKind(mutationKind),
1151 changeOptions[_CPKeyValueChangeSetMutationObjectsKey] = objects;
1152 changeOptions[_CPKeyValueChangeSetMutationKindKey] = mutationKind;
1154 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1157 - (void)didChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1159 var superClass = [
self class],
1160 methodSelector =
@selector(didChangeValueForKey:withSetMutation:usingObjects:),
1161 methodImp = class_getMethodImplementation(superClass, methodSelector);
1163 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1168 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1173 return self[KVOProxyKey]._nativeClass;
1178 return [[
self class] superclass];
1181 - (BOOL)isKindOfClass:(Class)aClass
1183 return [[
self class] isSubclassOfClass:aClass];
1186 - (BOOL)isMemberOfClass:(Class)aClass
1188 return [
self class] == aClass;
1193 return [
self class].name;
1197 @implementation _CPKVOModelDictionarySubclass :
CPObject 1202 - (void)removeAllObjects
1204 var keys = [
self allKeys],
1205 count = [keys count],
1208 for (; i < count; i++)
1209 [
self willChangeValueForKey:keys[i]];
1211 var superClass = [
self class],
1212 methodSelector =
@selector(removeAllObjects),
1213 methodImp = class_getMethodImplementation(superClass, methodSelector);
1215 methodImp(
self, methodSelector);
1217 for (i = 0; i < count; i++)
1218 [
self didChangeValueForKey:keys[i]];
1221 - (void)removeObjectForKey:(
id)aKey
1223 [
self willChangeValueForKey:aKey];
1225 var superClass = [
self class],
1226 methodSelector =
@selector(removeObjectForKey:),
1227 methodImp = class_getMethodImplementation(superClass, methodSelector);
1229 methodImp(
self, methodSelector, aKey);
1231 [
self didChangeValueForKey:aKey];
1234 - (void)setObject:(
id)anObject forKey:(id)aKey
1236 [
self willChangeValueForKey:aKey];
1238 var superClass = [
self class],
1239 methodSelector =
@selector(setObject:forKey:),
1240 methodImp = class_getMethodImplementation(superClass, methodSelector);
1242 methodImp(
self, methodSelector, anObject, aKey);
1244 [
self didChangeValueForKey:aKey];
1249 @implementation _CPKVOForwardingObserver :
CPObject 1262 - (id)initWithKeyPath:(
CPString)aKeyPath
object:(id)anObject observer:(
id)anObserver options:(unsigned)options context:(
id)aContext
1264 self = [
super init];
1266 _context = aContext;
1267 _observer = anObserver;
1271 var dotIndex = aKeyPath.indexOf(
'.');
1274 [
CPException raise:CPInvalidArgumentException
reason:"Created _CPKVOForwardingObserver without compound key path: " + aKeyPath];
1276 _firstPart = aKeyPath.substring(0, dotIndex);
1277 _secondPart = aKeyPath.substring(dotIndex + 1);
1280 [_object addObserver:self forKeyPath:_firstPart options:_options context:nil];
1283 _value = [_object valueForKey:_firstPart];
1286 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1291 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(id)anObject change:(
CPDictionary)changes context:(id)aContext
1293 if (aKeyPath === _firstPart)
1299 var oldValue = [_value valueForKeyPath:_secondPart];
1301 [pathChanges setObject:oldValue != null ? oldValue : [
CPNull null] forKey:CPKeyValueChangeOldKey];
1306 var newValue = [_object valueForKeyPath:_firstPart + "." + _secondPart];
1308 [pathChanges setObject:newValue != null ? newValue : [
CPNull null] forKey:CPKeyValueChangeNewKey];
1311 [_observer observeValueForKeyPath:_firstPart + "." + _secondPart ofObject:_object change:pathChanges context:_context];
1315 [_value removeObserver:self forKeyPath:_secondPart];
1317 _value = [_object valueForKey:_firstPart];
1320 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1325 [_observer observeValueForKeyPath:_firstPart + "." + aKeyPath ofObject:_object change:changes context:_context];
1332 [_value removeObserver:self forKeyPath:_secondPart];
1334 [_object removeObserver:self forKeyPath:_firstPart];
1344 var _CPKVOInfoMake =
function(anObserver, theOptions, aContext, aForwarder)
1347 observer: anObserver,
1348 options: theOptions,
1350 forwarder: aForwarder
Used to implement exception handling (creating & raising).
CPKeyValueChangeInsertion
CPKeyValueObservingOptionPrior
An object representation of nil.
CPDictionary inverseChangeDictionary()
CPKeyValueChangeReplacement
void raise:reason:(CPString aName, [reason] CPString aReason)
A collection of unique integers.
void removeObjectForKey:(id aKey)
id mutableSetValueForKeyPath:(id aKeyPath)
void setValue:forKeyPath:(id aValue, [forKeyPath] CPString aKeyPath)
A mutable key-value pair collection.
CPKeyValueObservingOptionInitial
An immutable string (collection of characters).
CPKeyValueChangeIndexesKey
id objectForKey:(id aKey)
CPKeyValueIntersectSetMutation
CPKeyValueObservingOptionNew
CPKeyValueChangeNotificationIsPriorKey
CPKeyValueUnionSetMutation
id mutableArrayValueForKeyPath:(id aKeyPath)
CPKeyValueMinusSetMutation
id indexSetWithIndex:(int anIndex)
void setObject:forKey:(id anObject, [forKey] id aKey)
CPKeyValueObservingOptionOld
id dictionaryWithObject:forKey:(id anObject, [forKey] id aKey)