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;
162 if ([[
self class] respondsToSelector:selector])
163 return objj_msgSend([
self class], selector);
168 + (CPSet)keyPathsForValuesAffectingValueForKey:(
CPString)aKey
170 var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1),
171 selector =
"keyPathsForValuesAffecting" + capitalizedKey;
173 if ([[
self class] respondsToSelector:selector])
174 return objj_msgSend([
self class], selector);
181 var changeKind = [aChange
objectForKey:CPKeyValueChangeKindKey],
182 oldValue = [aChange
objectForKey:CPKeyValueChangeOldKey],
183 newValue = [aChange
objectForKey:CPKeyValueChangeNewKey];
185 if (newValue === [
CPNull null])
191 var indexes = [aChange
objectForKey:CPKeyValueChangeIndexesKey];
225 changeKind = [
self objectForKey:CPKeyValueChangeKindKey];
231 forKey:CPKeyValueChangeNewKey];
235 forKey:CPKeyValueChangeOldKey];
242 forKey:CPKeyValueChangeKindKey];
246 forKey:CPKeyValueChangeOldKey];
255 forKey:CPKeyValueChangeKindKey];
259 forKey:CPKeyValueChangeNewKey];
264 return inverseChangeDictionary;
295 _CPKeyValueChangeSetMutationObjectsKey =
@"_CPKeyValueChangeSetMutationObjectsKey";
296 _CPKeyValueChangeSetMutationKindKey =
@"_CPKeyValueChangeSetMutationKindKey";
297 _CPKeyValueChangeSetMutationNewValueKey =
@"_CPKeyValueChangeSetMutationNewValueKey";
299 var _changeKindForSetMutationKind =
function(mutationKind)
301 switch (mutationKind)
317 @implementation _CPKVOProxy :
CPObject
324 Object _observersForKey;
325 int _observersForKeyLength;
332 + (id)proxyForObject:(
CPObject)anObject
334 var proxy = anObject[KVOProxyKey];
339 return [[
self alloc] initWithTarget:anObject];
342 - (id)initWithTarget:(
id)aTarget
344 if (
self = [super
init])
346 _targetObject = aTarget;
347 _nativeClass = [aTarget class];
348 _observersForKey = {};
351 _minOptionsForKey = {};
352 _observersForKeyLength = 0;
354 [
self _replaceClass];
355 aTarget[KVOProxyKey] =
self;
360 - (void)_replaceClass
362 var currentClass = _nativeClass,
363 kvoClassName =
"$KVO_" + class_getName(_nativeClass),
364 existingKVOClass = objj_lookUpClass(kvoClassName);
366 if (existingKVOClass)
368 _targetObject.isa = existingKVOClass;
369 _replacedKeys = existingKVOClass._replacedKeys;
373 var kvoClass = objj_allocateClassPair(currentClass, kvoClassName);
375 objj_registerClassPair(kvoClass);
377 _replacedKeys = [CPSet set];
378 kvoClass._replacedKeys = _replacedKeys;
381 var methods = class_copyMethodList(_CPKVOModelSubclass);
384 methods = methods.concat(class_copyMethodList(_CPKVOModelDictionarySubclass));
386 class_addMethods(kvoClass, methods);
388 _targetObject.isa = kvoClass;
391 - (void)_replaceModifiersForKey:(
CPString)aKey
393 if ([_replacedKeys containsObject:aKey] || ![_nativeClass automaticallyNotifiesObserversForKey:aKey])
396 [_replacedKeys addObject:aKey];
398 var theClass = _nativeClass,
399 KVOClass = _targetObject.isa,
400 capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
403 var setKey_selector = sel_getUid(
"set" + capitalizedKey +
":"),
404 setKey_method = class_getInstanceMethod(theClass, setKey_selector);
408 var setKey_method_imp = setKey_method.method_imp;
410 class_addMethod(KVOClass, setKey_selector,
function(
self, _cmd, anObject)
412 [
self willChangeValueForKey:aKey];
414 setKey_method_imp(
self, _cmd, anObject);
416 [
self didChangeValueForKey:aKey];
421 var _setKey_selector = sel_getUid(
"_set" + capitalizedKey +
":"),
422 _setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
426 var _setKey_method_imp = _setKey_method.method_imp;
428 class_addMethod(KVOClass, _setKey_selector,
function(
self, _cmd, anObject)
430 [
self willChangeValueForKey:aKey];
432 _setKey_method_imp(
self, _cmd, anObject);
434 [
self didChangeValueForKey:aKey];
439 var insertObject_inKeyAtIndex_selector = sel_getUid(
"insertObject:in" + capitalizedKey +
"AtIndex:"),
440 insertObject_inKeyAtIndex_method =
441 class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
443 insertKey_atIndexes_selector = sel_getUid(
"insert" + capitalizedKey +
":atIndexes:"),
444 insertKey_atIndexes_method =
445 class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
447 removeObjectFromKeyAtIndex_selector = sel_getUid(
"removeObjectFrom" + capitalizedKey +
"AtIndex:"),
448 removeObjectFromKeyAtIndex_method =
449 class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
451 removeKeyAtIndexes_selector = sel_getUid(
"remove" + capitalizedKey +
"AtIndexes:"),
452 removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
454 if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
455 (removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
457 if (insertObject_inKeyAtIndex_method)
459 var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
461 class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector,
function(
self, _cmd, anObject, anIndex)
463 [
self willChange:CPKeyValueChangeInsertion
467 insertObject_inKeyAtIndex_method_imp(
self, _cmd, anObject, anIndex);
469 [
self didChange:CPKeyValueChangeInsertion
475 if (insertKey_atIndexes_method)
477 var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
479 class_addMethod(KVOClass, insertKey_atIndexes_selector,
function(
self, _cmd, objects, indexes)
481 [
self willChange:CPKeyValueChangeInsertion
482 valuesAtIndexes:[indexes
copy]
485 insertKey_atIndexes_method_imp(
self, _cmd, objects, indexes);
487 [
self didChange:CPKeyValueChangeInsertion
488 valuesAtIndexes:[indexes
copy]
493 if (removeObjectFromKeyAtIndex_method)
495 var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
497 class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector,
function(
self, _cmd, anIndex)
499 [
self willChange:CPKeyValueChangeRemoval
503 removeObjectFromKeyAtIndex_method_imp(
self, _cmd, anIndex);
505 [
self didChange:CPKeyValueChangeRemoval
511 if (removeKeyAtIndexes_method)
513 var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
515 class_addMethod(KVOClass, removeKeyAtIndexes_selector,
function(
self, _cmd, indexes)
517 [
self willChange:CPKeyValueChangeRemoval
518 valuesAtIndexes:[indexes
copy]
521 removeKeyAtIndexes_method_imp(
self, _cmd, indexes);
523 [
self didChange:CPKeyValueChangeRemoval
524 valuesAtIndexes:[indexes
copy]
530 var replaceObjectInKeyAtIndex_withObject_selector =
531 sel_getUid(
"replaceObjectIn" + capitalizedKey +
"AtIndex:withObject:"),
532 replaceObjectInKeyAtIndex_withObject_method =
533 class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
535 if (replaceObjectInKeyAtIndex_withObject_method)
537 var replaceObjectInKeyAtIndex_withObject_method_imp =
538 replaceObjectInKeyAtIndex_withObject_method.method_imp;
540 class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
541 function(
self, _cmd, anIndex, anObject)
543 [
self willChange:CPKeyValueChangeReplacement
547 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, anIndex, anObject);
549 [
self didChange:CPKeyValueChangeReplacement
555 var replaceKeyAtIndexes_withKey_selector =
556 sel_getUid(
"replace" + capitalizedKey +
"AtIndexes:with" + capitalizedKey +
":"),
557 replaceKeyAtIndexes_withKey_method =
558 class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
560 if (replaceKeyAtIndexes_withKey_method)
562 var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
564 class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector,
function(
self, _cmd, indexes, objects)
566 [
self willChange:CPKeyValueChangeReplacement
567 valuesAtIndexes:[indexes
copy]
570 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, indexes, objects);
572 [
self didChange:CPKeyValueChangeReplacement
573 valuesAtIndexes:[indexes
copy]
580 var addKeyObject_selector = sel_getUid(
"add" + capitalizedKey +
"Object:"),
581 addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
583 addKey_selector = sel_getUid(
"add" + capitalizedKey +
":"),
584 addKey_method = class_getInstanceMethod(theClass, addKey_selector),
586 removeKeyObject_selector = sel_getUid(
"remove" + capitalizedKey +
"Object:"),
587 removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
589 removeKey_selector = sel_getUid(
"remove" + capitalizedKey +
":"),
590 removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
592 if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
594 if (addKeyObject_method)
596 var addKeyObject_method_imp = addKeyObject_method.method_imp;
598 class_addMethod(KVOClass, addKeyObject_selector,
function(
self, _cmd, anObject)
600 [
self willChangeValueForKey:aKey
601 withSetMutation:CPKeyValueUnionSetMutation
602 usingObjects:[CPSet setWithObject:anObject]];
604 addKeyObject_method_imp(
self, _cmd, anObject);
606 [
self didChangeValueForKey:aKey
607 withSetMutation:CPKeyValueUnionSetMutation
608 usingObjects:[CPSet setWithObject:anObject]];
614 var addKey_method_imp = addKey_method.method_imp;
616 class_addMethod(KVOClass, addKey_selector,
function(
self, _cmd, objects)
618 [
self willChangeValueForKey:aKey
619 withSetMutation:CPKeyValueUnionSetMutation
620 usingObjects:[objects copy]];
622 addKey_method_imp(
self, _cmd, objects);
624 [
self didChangeValueForKey:aKey
625 withSetMutation:CPKeyValueUnionSetMutation
626 usingObjects:[objects copy]];
630 if (removeKeyObject_method)
632 var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
634 class_addMethod(KVOClass, removeKeyObject_selector,
function(
self, _cmd, anObject)
636 [
self willChangeValueForKey:aKey
637 withSetMutation:CPKeyValueMinusSetMutation
638 usingObjects:[CPSet setWithObject:anObject]];
640 removeKeyObject_method_imp(
self, _cmd, anObject);
642 [
self didChangeValueForKey:aKey
643 withSetMutation:CPKeyValueMinusSetMutation
644 usingObjects:[CPSet setWithObject:anObject]];
648 if (removeKey_method)
650 var removeKey_method_imp = removeKey_method.method_imp;
652 class_addMethod(KVOClass, removeKey_selector,
function(
self, _cmd, objects)
654 [
self willChangeValueForKey:aKey
655 withSetMutation:CPKeyValueMinusSetMutation
656 usingObjects:[objects copy]];
658 removeKey_method_imp(
self, _cmd, objects);
660 [
self didChangeValueForKey:aKey
661 withSetMutation:CPKeyValueMinusSetMutation
662 usingObjects:[objects copy]];
667 var intersectKey_selector = sel_getUid(
"intersect" + capitalizedKey +
":"),
668 intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
670 if (intersectKey_method)
672 var intersectKey_method_imp = intersectKey_method.method_imp;
674 class_addMethod(KVOClass, intersectKey_selector,
function(
self, _cmd, aSet)
676 [
self willChangeValueForKey:aKey
677 withSetMutation:CPKeyValueIntersectSetMutation
678 usingObjects:[aSet copy]];
680 intersectKey_method_imp(
self, _cmd, aSet);
682 [
self didChangeValueForKey:aKey
683 withSetMutation:CPKeyValueIntersectSetMutation
684 usingObjects:[aSet copy]];
689 var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects],
690 affectingKeysCount = affectingKeys ? affectingKeys.length : 0;
692 if (!affectingKeysCount)
695 var dependentKeysForClass = _nativeClass[DependentKeysKey];
697 if (!dependentKeysForClass)
699 dependentKeysForClass = {};
700 _nativeClass[DependentKeysKey] = dependentKeysForClass;
703 while (affectingKeysCount--)
705 var affectingKey = affectingKeys[affectingKeysCount],
706 affectedKeys = dependentKeysForClass[affectingKey];
710 affectedKeys = [CPSet new];
711 dependentKeysForClass[affectingKey] = affectedKeys;
714 [affectedKeys addObject:aKey];
719 if (affectingKey.indexOf(
@".") !== -1)
720 [_targetObject addObserver:self forKeyPath:affectingKey options:CPKeyValueObservingOptionPrior | kvoNewAndOld context:nil];
722 [
self _replaceModifiersForKey:affectingKey];
726 - (void)observeValueForKeyPath:(
CPString)theKeyPath ofObject:(
id)theObject change:(CPDictionary)theChanges context:(
id)theContext
729 var dependentKeysForClass = _nativeClass[DependentKeysKey],
730 dependantKeys = [dependentKeysForClass[theKeyPath] allObjects],
731 isBeforeFlag = !![theChanges
objectForKey:CPKeyValueChangeNotificationIsPriorKey];
733 for (var i = 0; i < [dependantKeys count]; i++)
735 var dependantKey = [dependantKeys objectAtIndex:i];
736 [
self _sendNotificationsForKey:dependantKey changeOptions:theChanges isBefore:isBeforeFlag];
740 - (void)_addObserver:(
id)anObserver forKeyPath:(
CPString)aPath options:(CPKeyValueObservingOptions)options context:(
id)aContext
747 if (aPath.indexOf(
'.') !==
CPNotFound && aPath.charAt(0) !==
'@')
748 forwarder = [[_CPKVOForwardingObserver alloc] initWithKeyPath:aPath
object:_targetObject observer:anObserver options:options context:aContext];
750 [
self _replaceModifiersForKey:aPath];
752 var observers = _observersForKey[aPath];
757 _observersForKey[aPath] = observers;
758 _observersForKeyLength++;
761 [observers setObject:_CPKVOInfoMake(anObserver, options, aContext, forwarder) forKey:[anObserver UID]];
769 var newValue = [_targetObject valueForKeyPath:aPath];
779 [anObserver observeValueForKeyPath:aPath ofObject:_targetObject change:changes context:aContext];
783 - (void)_removeObserver:(
id)anObserver forKeyPath:(
CPString)aPath
785 var observers = _observersForKey[aPath];
791 CPLog.warn(
@"Cannot remove an observer %@ for the key path \"%@\
" from %@ because it is not registered as an observer.", _targetObject, aPath, anObserver);
800 var observer = [observers objectForKey:[anObserver UID]],
801 forwarder = observer ? observer.forwarder : nil;
803 [forwarder finalize];
806 [observers removeObjectForKey:[anObserver UID]];
808 if (![observers count])
810 _observersForKeyLength--;
811 delete _observersForKey[aPath];
814 if (!_observersForKeyLength)
816 _targetObject.isa = _nativeClass;
817 delete _targetObject[KVOProxyKey];
823 - (void)_sendNotificationsForKey:(
CPString)aKey changeOptions:(CPDictionary)changeOptions isBefore:(BOOL)isBefore
825 var changes = _changesForKey[aKey],
826 observers = [_observersForKey[aKey] allValues],
827 observersMinimumOptions = 0;
834 var level = _nestingForKey[aKey];
839 _nestingForKey[aKey] = level + 1;
844 _nestingForKey[aKey] = 1;
847 var count = observers ? observers.length : 0;
851 var observerInfo = observers[count];
853 observersMinimumOptions |= observerInfo.options &
kvoNewAndOld;
856 _minOptionsForKey[aKey] = observersMinimumOptions;
857 changes = changeOptions;
861 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
862 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
866 var setMutationObjects = [changes[_CPKeyValueChangeSetMutationObjectsKey] copy],
867 setExistingObjects = [[_targetObject valueForKey: aKey] copy];
871 [setExistingObjects intersectSet: setMutationObjects];
872 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
876 [setExistingObjects minusSet: setMutationObjects];
877 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
883 [setMutationObjects minusSet: setExistingObjects];
886 changes[_CPKeyValueChangeSetMutationNewValueKey] = setMutationObjects;
891 var type = [changes objectForKey:CPKeyValueChangeKindKey];
897 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
898 [changes setValue:newValues forKey:CPKeyValueChangeOldKey];
903 var oldValue = [_targetObject valueForKey:aKey];
905 if (oldValue === nil || oldValue === undefined)
908 [changes setObject:oldValue forKey:CPKeyValueChangeOldKey];
913 [changes setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey];
914 _changesForKey[aKey] = changes;
921 var level = _nestingForKey[aKey];
923 if (!changes || !level)
925 if (_targetObject._willChangeMessageCounter && _targetObject._willChangeMessageCounter[aKey])
928 _targetObject._willChangeMessageCounter[aKey] -= 1;
930 if (!_targetObject._willChangeMessageCounter[aKey])
931 delete _targetObject._willChangeMessageCounter[aKey];
936 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
939 _nestingForKey[aKey] = level - 1;
948 delete _nestingForKey[aKey];
950 [changes removeObjectForKey:CPKeyValueChangeNotificationIsPriorKey];
952 observersMinimumOptions = _minOptionsForKey[aKey];
956 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
957 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
963 var newValue = changes[_CPKeyValueChangeSetMutationNewValueKey];
964 [changes setValue:newValue forKey:CPKeyValueChangeNewKey];
967 delete changes[_CPKeyValueChangeSetMutationNewValueKey];
968 delete changes[_CPKeyValueChangeSetMutationObjectsKey];
969 delete changes[_CPKeyValueChangeSetMutationKindKey];
973 var type = [changes objectForKey:CPKeyValueChangeKindKey];
979 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
980 [changes setValue:newValues forKey:CPKeyValueChangeNewKey];
985 var newValue = [_targetObject valueForKey:aKey];
987 if (newValue === nil || newValue === undefined)
990 [changes setObject:newValue forKey:CPKeyValueChangeNewKey];
994 delete _minOptionsForKey[aKey];
995 delete _changesForKey[aKey];
998 var count = observers ? observers.length : 0,
1003 var observerInfo = observers[count],
1004 options = observerInfo.options,
1006 observerChanges = nil;
1013 observerChanges = changes;
1015 onlyNewAndOldOptions &= ~CPKeyValueObservingOptionNew;
1020 observerChanges = changes;
1023 if (observerChanges)
1027 if (onlyNewAndOldOptions !== observersMinimumOptions)
1030 observerChanges = changesCache[onlyNewAndOldOptions];
1031 if (!observerChanges)
1034 changesCache[onlyNewAndOldOptions] = observerChanges = [changes mutableCopy];
1035 if (!(onlyNewAndOldOptions & CPKeyValueObservingOptionOld))
1037 if (!(onlyNewAndOldOptions & CPKeyValueObservingOptionNew))
1041 [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:observerChanges context:observerInfo.context];
1045 var dependentKeysMap = _nativeClass[DependentKeysKey];
1047 if (!dependentKeysMap)
1050 var dependentKeyPaths = [dependentKeysMap[aKey] allObjects];
1052 if (!dependentKeyPaths)
1056 count = [dependentKeyPaths count];
1058 for (; index < count; ++index)
1060 var keyPath = dependentKeyPaths[index];
1062 [
self _sendNotificationsForKey:keyPath
1063 changeOptions:isBefore ? [changeOptions
copy] : _changesForKey[keyPath]
1069 @implementation _CPKVOModelSubclass :
CPObject
1074 - (void)willChangeValueForKey:(
CPString)aKey
1076 var superClass = [
self class],
1077 methodSelector =
@selector(willChangeValueForKey:),
1078 methodImp = class_getMethodImplementation(superClass, methodSelector);
1080 methodImp(
self, methodSelector, aKey);
1087 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1090 - (void)didChangeValueForKey:(
CPString)aKey
1092 var superClass = [
self class],
1093 methodSelector =
@selector(didChangeValueForKey:),
1094 methodImp = class_getMethodImplementation(superClass, methodSelector);
1096 methodImp(
self, methodSelector, aKey);
1101 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1104 - (void)willChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1106 var superClass = [
self class],
1107 methodSelector =
@selector(willChange:valuesAtIndexes:forKey:),
1108 methodImp = class_getMethodImplementation(superClass, methodSelector);
1110 methodImp(
self, methodSelector, change, indexes, aKey);
1117 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1120 - (void)didChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1122 var superClass = [
self class],
1123 methodSelector =
@selector(didChange:valuesAtIndexes:forKey:),
1124 methodImp = class_getMethodImplementation(superClass, methodSelector);
1126 methodImp(
self, methodSelector, change, indexes, aKey);
1131 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1134 - (void)willChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1136 var superClass = [
self class],
1137 methodSelector =
@selector(willChangeValueForKey:withSetMutation:usingObjects:),
1138 methodImp = class_getMethodImplementation(superClass, methodSelector);
1140 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1145 var changeKind = _changeKindForSetMutationKind(mutationKind),
1149 changeOptions[_CPKeyValueChangeSetMutationObjectsKey] = objects;
1150 changeOptions[_CPKeyValueChangeSetMutationKindKey] = mutationKind;
1152 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1155 - (void)didChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1157 var superClass = [
self class],
1158 methodSelector =
@selector(didChangeValueForKey:withSetMutation:usingObjects:),
1159 methodImp = class_getMethodImplementation(superClass, methodSelector);
1161 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1166 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1171 return self[KVOProxyKey]._nativeClass;
1176 return [[
self class] superclass];
1179 - (BOOL)isKindOfClass:(Class)aClass
1181 return [[
self class] isSubclassOfClass:aClass];
1184 - (BOOL)isMemberOfClass:(Class)aClass
1186 return [
self class] == aClass;
1191 return [
self class].name;
1195 @implementation _CPKVOModelDictionarySubclass :
CPObject
1200 - (void)removeAllObjects
1202 var keys = [
self allKeys],
1203 count = [keys count],
1206 for (; i < count; i++)
1207 [self willChangeValueForKey:keys[i]];
1209 var superClass = [
self class],
1210 methodSelector =
@selector(removeAllObjects),
1211 methodImp = class_getMethodImplementation(superClass, methodSelector);
1213 methodImp(
self, methodSelector);
1215 for (i = 0; i < count; i++)
1216 [self didChangeValueForKey:keys[i]];
1219 - (void)removeObjectForKey:(
id)aKey
1221 [
self willChangeValueForKey:aKey];
1223 var superClass = [
self class],
1224 methodSelector =
@selector(removeObjectForKey:),
1225 methodImp = class_getMethodImplementation(superClass, methodSelector);
1227 methodImp(
self, methodSelector, aKey);
1229 [
self didChangeValueForKey:aKey];
1232 - (void)setObject:(
id)anObject forKey:(
id)aKey
1234 [
self willChangeValueForKey:aKey];
1236 var superClass = [
self class],
1237 methodSelector =
@selector(setObject:forKey:),
1238 methodImp = class_getMethodImplementation(superClass, methodSelector);
1240 methodImp(
self, methodSelector, anObject, aKey);
1242 [
self didChangeValueForKey:aKey];
1247 @implementation _CPKVOForwardingObserver :
CPObject
1260 - (id)initWithKeyPath:(
CPString)aKeyPath object:(
id)anObject observer:(
id)anObserver options:(
unsigned)options context:(
id)aContext
1262 self = [
super init];
1264 _context = aContext;
1265 _observer = anObserver;
1269 var dotIndex = aKeyPath.indexOf(
'.');
1272 [
CPException raise:CPInvalidArgumentException
reason:"Created _CPKVOForwardingObserver without compound key path: " + aKeyPath];
1274 _firstPart = aKeyPath.substring(0, dotIndex);
1275 _secondPart = aKeyPath.substring(dotIndex + 1);
1278 [_object addObserver:self forKeyPath:_firstPart options:_options context:nil];
1281 _value = [_object valueForKey:_firstPart];
1284 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1289 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(CPDictionary)changes context:(
id)aContext
1291 if (aKeyPath === _firstPart)
1295 if (_options & CPKeyValueObservingOptionOld)
1297 var oldValue = [_value valueForKeyPath:_secondPart];
1299 [pathChanges setObject:oldValue != null ? oldValue : [
CPNull null] forKey:CPKeyValueChangeOldKey];
1302 if (_options & CPKeyValueObservingOptionNew)
1304 var newValue = [_object valueForKeyPath:_firstPart + "." + _secondPart];
1306 [pathChanges setObject:newValue != null ? newValue : [
CPNull null] forKey:CPKeyValueChangeNewKey];
1309 [_observer observeValueForKeyPath:_firstPart + "." + _secondPart ofObject:_object change:pathChanges context:_context];
1313 [_value removeObserver:self forKeyPath:_secondPart];
1315 _value = [_object valueForKey:_firstPart];
1318 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1323 [_observer observeValueForKeyPath:_firstPart + "." + aKeyPath ofObject:_object change:changes context:_context];
1330 [_value removeObserver:self forKeyPath:_secondPart];
1332 [_object removeObserver:self forKeyPath:_firstPart];
1342 var _CPKVOInfoMake =
function(anObserver, theOptions, aContext, aForwarder)
1345 observer: anObserver,
1346 options: theOptions,
1348 forwarder: aForwarder