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])
397 [_replacedKeys addObject:aKey];
399 var theClass = _nativeClass,
400 KVOClass = _targetObject.isa,
401 capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
404 var setKey_selector = sel_getUid(
"set" + capitalizedKey +
":"),
405 setKey_method = class_getInstanceMethod(theClass, setKey_selector);
409 var setKey_method_imp = setKey_method.method_imp;
411 class_addMethod(KVOClass, setKey_selector,
function(
self, _cmd, anObject)
413 [
self willChangeValueForKey:aKey];
415 setKey_method_imp(
self, _cmd, anObject);
417 [
self didChangeValueForKey:aKey];
418 }, setKey_method.method_types);
422 var _setKey_selector = sel_getUid(
"_set" + capitalizedKey +
":"),
423 _setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
427 var _setKey_method_imp = _setKey_method.method_imp;
429 class_addMethod(KVOClass, _setKey_selector,
function(
self, _cmd, anObject)
431 [
self willChangeValueForKey:aKey];
433 _setKey_method_imp(
self, _cmd, anObject);
435 [
self didChangeValueForKey:aKey];
436 }, _setKey_method.method_types);
440 var insertObject_inKeyAtIndex_selector = sel_getUid(
"insertObject:in" + capitalizedKey +
"AtIndex:"),
441 insertObject_inKeyAtIndex_method =
442 class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
444 insertKey_atIndexes_selector = sel_getUid(
"insert" + capitalizedKey +
":atIndexes:"),
445 insertKey_atIndexes_method =
446 class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
448 removeObjectFromKeyAtIndex_selector = sel_getUid(
"removeObjectFrom" + capitalizedKey +
"AtIndex:"),
449 removeObjectFromKeyAtIndex_method =
450 class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
452 removeKeyAtIndexes_selector = sel_getUid(
"remove" + capitalizedKey +
"AtIndexes:"),
453 removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
455 if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
456 (removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
458 if (insertObject_inKeyAtIndex_method)
460 var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
462 class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector,
function(
self, _cmd, anObject, anIndex)
464 [
self willChange:CPKeyValueChangeInsertion
468 insertObject_inKeyAtIndex_method_imp(
self, _cmd, anObject, anIndex);
470 [
self didChange:CPKeyValueChangeInsertion
473 }, insertObject_inKeyAtIndex_method.method_types);
476 if (insertKey_atIndexes_method)
478 var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
480 class_addMethod(KVOClass, insertKey_atIndexes_selector,
function(
self, _cmd, objects, indexes)
482 [
self willChange:CPKeyValueChangeInsertion
483 valuesAtIndexes:[indexes
copy]
486 insertKey_atIndexes_method_imp(
self, _cmd, objects, indexes);
488 [
self didChange:CPKeyValueChangeInsertion
489 valuesAtIndexes:[indexes
copy]
491 }, insertKey_atIndexes_method.method_types);
494 if (removeObjectFromKeyAtIndex_method)
496 var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
498 class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector,
function(
self, _cmd, anIndex)
500 [
self willChange:CPKeyValueChangeRemoval
504 removeObjectFromKeyAtIndex_method_imp(
self, _cmd, anIndex);
506 [
self didChange:CPKeyValueChangeRemoval
509 }, removeObjectFromKeyAtIndex_method.method_types);
512 if (removeKeyAtIndexes_method)
514 var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
516 class_addMethod(KVOClass, removeKeyAtIndexes_selector,
function(
self, _cmd, indexes)
518 [
self willChange:CPKeyValueChangeRemoval
519 valuesAtIndexes:[indexes
copy]
522 removeKeyAtIndexes_method_imp(
self, _cmd, indexes);
524 [
self didChange:CPKeyValueChangeRemoval
525 valuesAtIndexes:[indexes
copy]
527 }, removeKeyAtIndexes_method.method_types);
531 var replaceObjectInKeyAtIndex_withObject_selector =
532 sel_getUid(
"replaceObjectIn" + capitalizedKey +
"AtIndex:withObject:"),
533 replaceObjectInKeyAtIndex_withObject_method =
534 class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
536 if (replaceObjectInKeyAtIndex_withObject_method)
538 var replaceObjectInKeyAtIndex_withObject_method_imp =
539 replaceObjectInKeyAtIndex_withObject_method.method_imp;
541 class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
542 function(
self, _cmd, anIndex, anObject)
544 [
self willChange:CPKeyValueChangeReplacement
548 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, anIndex, anObject);
550 [
self didChange:CPKeyValueChangeReplacement
553 }, replaceObjectInKeyAtIndex_withObject_method.method_types);
556 var replaceKeyAtIndexes_withKey_selector =
557 sel_getUid(
"replace" + capitalizedKey +
"AtIndexes:with" + capitalizedKey +
":"),
558 replaceKeyAtIndexes_withKey_method =
559 class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
561 if (replaceKeyAtIndexes_withKey_method)
563 var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
565 class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector,
function(
self, _cmd, indexes, objects)
567 [
self willChange:CPKeyValueChangeReplacement
568 valuesAtIndexes:[indexes
copy]
571 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, indexes, objects);
573 [
self didChange:CPKeyValueChangeReplacement
574 valuesAtIndexes:[indexes
copy]
576 }, replaceKeyAtIndexes_withKey_method.method_types);
581 var addKeyObject_selector = sel_getUid(
"add" + capitalizedKey +
"Object:"),
582 addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
584 addKey_selector = sel_getUid(
"add" + capitalizedKey +
":"),
585 addKey_method = class_getInstanceMethod(theClass, addKey_selector),
587 removeKeyObject_selector = sel_getUid(
"remove" + capitalizedKey +
"Object:"),
588 removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
590 removeKey_selector = sel_getUid(
"remove" + capitalizedKey +
":"),
591 removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
593 if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
595 if (addKeyObject_method)
597 var addKeyObject_method_imp = addKeyObject_method.method_imp;
599 class_addMethod(KVOClass, addKeyObject_selector,
function(
self, _cmd, anObject)
601 [
self willChangeValueForKey:aKey
602 withSetMutation:CPKeyValueUnionSetMutation
603 usingObjects:[CPSet setWithObject:anObject]];
605 addKeyObject_method_imp(
self, _cmd, anObject);
607 [
self didChangeValueForKey:aKey
608 withSetMutation:CPKeyValueUnionSetMutation
609 usingObjects:[CPSet setWithObject:anObject]];
610 }, addKeyObject_method.method_types);
615 var addKey_method_imp = addKey_method.method_imp;
617 class_addMethod(KVOClass, addKey_selector,
function(
self, _cmd, objects)
619 [
self willChangeValueForKey:aKey
620 withSetMutation:CPKeyValueUnionSetMutation
621 usingObjects:[objects copy]];
623 addKey_method_imp(
self, _cmd, objects);
625 [
self didChangeValueForKey:aKey
626 withSetMutation:CPKeyValueUnionSetMutation
627 usingObjects:[objects copy]];
628 }, addKey_method.method_types);
631 if (removeKeyObject_method)
633 var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
635 class_addMethod(KVOClass, removeKeyObject_selector,
function(
self, _cmd, anObject)
637 [
self willChangeValueForKey:aKey
638 withSetMutation:CPKeyValueMinusSetMutation
639 usingObjects:[CPSet setWithObject:anObject]];
641 removeKeyObject_method_imp(
self, _cmd, anObject);
643 [
self didChangeValueForKey:aKey
644 withSetMutation:CPKeyValueMinusSetMutation
645 usingObjects:[CPSet setWithObject:anObject]];
646 }, removeKeyObject_method.method_types);
649 if (removeKey_method)
651 var removeKey_method_imp = removeKey_method.method_imp;
653 class_addMethod(KVOClass, removeKey_selector,
function(
self, _cmd, objects)
655 [
self willChangeValueForKey:aKey
656 withSetMutation:CPKeyValueMinusSetMutation
657 usingObjects:[objects copy]];
659 removeKey_method_imp(
self, _cmd, objects);
661 [
self didChangeValueForKey:aKey
662 withSetMutation:CPKeyValueMinusSetMutation
663 usingObjects:[objects copy]];
664 }, removeKey_method.method_types);
668 var intersectKey_selector = sel_getUid(
"intersect" + capitalizedKey +
":"),
669 intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
671 if (intersectKey_method)
673 var intersectKey_method_imp = intersectKey_method.method_imp;
675 class_addMethod(KVOClass, intersectKey_selector,
function(
self, _cmd, aSet)
677 [
self willChangeValueForKey:aKey
678 withSetMutation:CPKeyValueIntersectSetMutation
679 usingObjects:[aSet copy]];
681 intersectKey_method_imp(
self, _cmd, aSet);
683 [
self didChangeValueForKey:aKey
684 withSetMutation:CPKeyValueIntersectSetMutation
685 usingObjects:[aSet copy]];
686 }, 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)
722 [_targetObject addObserver:self forKeyPath:affectingKey options:CPKeyValueObservingOptionPrior | kvoNewAndOld context:nil];
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)
1296 var isBeforeFlag = !![changes
objectForKey:CPKeyValueChangeNotificationIsPriorKey];
1299 [pathChanges setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey];
1303 var oldValue = [_value valueForKeyPath:_secondPart];
1305 [pathChanges setObject:oldValue != null ? oldValue : [
CPNull null] forKey:CPKeyValueChangeOldKey];
1310 var newValue = [_object valueForKeyPath:_firstPart + "." + _secondPart];
1312 [pathChanges setObject:newValue != null ? newValue : [
CPNull null] forKey:CPKeyValueChangeNewKey];
1315 [_observer observeValueForKeyPath:_firstPart + "." + _secondPart ofObject:_object change:pathChanges context:_context];
1318 if (!isBeforeFlag) {
1321 [_value removeObserver:self forKeyPath:_secondPart];
1323 _value = [_object valueForKey:_firstPart];
1326 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1332 [_observer observeValueForKeyPath:_firstPart + "." + aKeyPath ofObject:_object change:changes context:_context];
1339 [_value removeObserver:self forKeyPath:_secondPart];
1341 [_object removeObserver:self forKeyPath:_firstPart];
1351 var _CPKVOInfoMake =
function(anObserver, theOptions, aContext, aForwarder)
1354 observer: anObserver,
1355 options: theOptions,
1357 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)