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])
189 return [
self setValue:newValue forKeyPath:aKeyPath];
191 var indexes = [aChange
objectForKey:CPKeyValueChangeIndexesKey];
197 [[
self mutableArrayValueForKeyPath:aKeyPath] insertObjects:newValue atIndexes:indexes];
200 [[
self mutableArrayValueForKeyPath:aKeyPath] removeObjectsAtIndexes:indexes];
203 [[
self mutableArrayValueForKeyPath:aKeyPath] replaceObjectAtIndexes:indexes withObjects:newValue];
208 [[
self mutableSetValueForKeyPath:aKeyPath] unionSet:newValue];
211 [[
self mutableSetValueForKeyPath:aKeyPath] minusSet:oldValue];
214 [[
self mutableSetValueForKeyPath:aKeyPath] setSet:newValue];
224 var inverseChangeDictionary = [
self mutableCopy],
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
323 Object _observersForKey;
324 int _observersForKeyLength;
331 + (id)proxyForObject:(
CPObject)anObject
333 var proxy = anObject[KVOProxyKey];
338 return [[
self alloc] initWithTarget:anObject];
341 - (id)initWithTarget:(
id)aTarget
343 if (
self = [super init])
345 _targetObject = aTarget;
346 _nativeClass = [aTarget class];
347 _observersForKey = {};
350 _observersForKeyLength = 0;
352 [
self _replaceClass];
353 aTarget[KVOProxyKey] =
self;
358 - (void)_replaceClass
360 var currentClass = _nativeClass,
361 kvoClassName =
"$KVO_" + class_getName(_nativeClass),
362 existingKVOClass = objj_lookUpClass(kvoClassName);
364 if (existingKVOClass)
366 _targetObject.isa = existingKVOClass;
367 _replacedKeys = existingKVOClass._replacedKeys;
371 var kvoClass = objj_allocateClassPair(currentClass, kvoClassName);
373 objj_registerClassPair(kvoClass);
375 _replacedKeys = [CPSet set];
376 kvoClass._replacedKeys = _replacedKeys;
379 var methods = class_copyMethodList(_CPKVOModelSubclass);
382 methods = methods.concat(class_copyMethodList(_CPKVOModelDictionarySubclass));
384 class_addMethods(kvoClass, methods);
386 _targetObject.isa = kvoClass;
389 - (void)_replaceModifiersForKey:(
CPString)aKey
391 if ([_replacedKeys containsObject:aKey] || ![_nativeClass automaticallyNotifiesObserversForKey:aKey])
394 [_replacedKeys addObject:aKey];
396 var theClass = _nativeClass,
397 KVOClass = _targetObject.isa,
398 capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
401 var setKey_selector = sel_getUid(
"set" + capitalizedKey +
":"),
402 setKey_method = class_getInstanceMethod(theClass, setKey_selector);
406 var setKey_method_imp = setKey_method.method_imp;
408 class_addMethod(KVOClass, setKey_selector,
function(
self, _cmd, anObject)
410 [
self willChangeValueForKey:aKey];
412 setKey_method_imp(
self, _cmd, anObject);
414 [
self didChangeValueForKey:aKey];
419 var _setKey_selector = sel_getUid(
"_set" + capitalizedKey +
":"),
420 _setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
424 var _setKey_method_imp = _setKey_method.method_imp;
426 class_addMethod(KVOClass, _setKey_selector,
function(
self, _cmd, anObject)
428 [
self willChangeValueForKey:aKey];
430 _setKey_method_imp(
self, _cmd, anObject);
432 [
self didChangeValueForKey:aKey];
437 var insertObject_inKeyAtIndex_selector = sel_getUid(
"insertObject:in" + capitalizedKey +
"AtIndex:"),
438 insertObject_inKeyAtIndex_method =
439 class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
441 insertKey_atIndexes_selector = sel_getUid(
"insert" + capitalizedKey +
":atIndexes:"),
442 insertKey_atIndexes_method =
443 class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
445 removeObjectFromKeyAtIndex_selector = sel_getUid(
"removeObjectFrom" + capitalizedKey +
"AtIndex:"),
446 removeObjectFromKeyAtIndex_method =
447 class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
449 removeKeyAtIndexes_selector = sel_getUid(
"remove" + capitalizedKey +
"AtIndexes:"),
450 removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
452 if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
453 (removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
455 if (insertObject_inKeyAtIndex_method)
457 var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
459 class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector,
function(
self, _cmd, anObject, anIndex)
461 [
self willChange:CPKeyValueChangeInsertion
465 insertObject_inKeyAtIndex_method_imp(
self, _cmd, anObject, anIndex);
467 [
self didChange:CPKeyValueChangeInsertion
473 if (insertKey_atIndexes_method)
475 var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
477 class_addMethod(KVOClass, insertKey_atIndexes_selector,
function(
self, _cmd, objects, indexes)
479 [
self willChange:CPKeyValueChangeInsertion
480 valuesAtIndexes:[indexes
copy]
483 insertKey_atIndexes_method_imp(
self, _cmd, objects, indexes);
485 [
self didChange:CPKeyValueChangeInsertion
486 valuesAtIndexes:[indexes
copy]
491 if (removeObjectFromKeyAtIndex_method)
493 var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
495 class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector,
function(
self, _cmd, anIndex)
497 [
self willChange:CPKeyValueChangeRemoval
501 removeObjectFromKeyAtIndex_method_imp(
self, _cmd, anIndex);
503 [
self didChange:CPKeyValueChangeRemoval
509 if (removeKeyAtIndexes_method)
511 var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
513 class_addMethod(KVOClass, removeKeyAtIndexes_selector,
function(
self, _cmd, indexes)
515 [
self willChange:CPKeyValueChangeRemoval
516 valuesAtIndexes:[indexes
copy]
519 removeKeyAtIndexes_method_imp(
self, _cmd, indexes);
521 [
self didChange:CPKeyValueChangeRemoval
522 valuesAtIndexes:[indexes
copy]
528 var replaceObjectInKeyAtIndex_withObject_selector =
529 sel_getUid(
"replaceObjectIn" + capitalizedKey +
"AtIndex:withObject:"),
530 replaceObjectInKeyAtIndex_withObject_method =
531 class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
533 if (replaceObjectInKeyAtIndex_withObject_method)
535 var replaceObjectInKeyAtIndex_withObject_method_imp =
536 replaceObjectInKeyAtIndex_withObject_method.method_imp;
538 class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
539 function(
self, _cmd, anIndex, anObject)
541 [
self willChange:CPKeyValueChangeReplacement
545 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, anIndex, anObject);
547 [
self didChange:CPKeyValueChangeReplacement
553 var replaceKeyAtIndexes_withKey_selector =
554 sel_getUid(
"replace" + capitalizedKey +
"AtIndexes:with" + capitalizedKey +
":"),
555 replaceKeyAtIndexes_withKey_method =
556 class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
558 if (replaceKeyAtIndexes_withKey_method)
560 var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
562 class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector,
function(
self, _cmd, indexes, objects)
564 [
self willChange:CPKeyValueChangeReplacement
565 valuesAtIndexes:[indexes
copy]
568 replaceObjectInKeyAtIndex_withObject_method_imp(
self, _cmd, indexes, objects);
570 [
self didChange:CPKeyValueChangeReplacement
571 valuesAtIndexes:[indexes
copy]
578 var addKeyObject_selector = sel_getUid(
"add" + capitalizedKey +
"Object:"),
579 addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
581 addKey_selector = sel_getUid(
"add" + capitalizedKey +
":"),
582 addKey_method = class_getInstanceMethod(theClass, addKey_selector),
584 removeKeyObject_selector = sel_getUid(
"remove" + capitalizedKey +
"Object:"),
585 removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
587 removeKey_selector = sel_getUid(
"remove" + capitalizedKey +
":"),
588 removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
590 if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
592 if (addKeyObject_method)
594 var addKeyObject_method_imp = addKeyObject_method.method_imp;
596 class_addMethod(KVOClass, addKeyObject_selector,
function(
self, _cmd, anObject)
598 [
self willChangeValueForKey:aKey
599 withSetMutation:CPKeyValueUnionSetMutation
600 usingObjects:[CPSet setWithObject:anObject]];
602 addKeyObject_method_imp(
self, _cmd, anObject);
604 [
self didChangeValueForKey:aKey
605 withSetMutation:CPKeyValueUnionSetMutation
606 usingObjects:[CPSet setWithObject:anObject]];
612 var addKey_method_imp = addKey_method.method_imp;
614 class_addMethod(KVOClass, addKey_selector,
function(
self, _cmd, objects)
616 [
self willChangeValueForKey:aKey
617 withSetMutation:CPKeyValueUnionSetMutation
618 usingObjects:[objects copy]];
620 addKey_method_imp(
self, _cmd, objects);
622 [
self didChangeValueForKey:aKey
623 withSetMutation:CPKeyValueUnionSetMutation
624 usingObjects:[objects copy]];
628 if (removeKeyObject_method)
630 var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
632 class_addMethod(KVOClass, removeKeyObject_selector,
function(
self, _cmd, anObject)
634 [
self willChangeValueForKey:aKey
635 withSetMutation:CPKeyValueMinusSetMutation
636 usingObjects:[CPSet setWithObject:anObject]];
638 removeKeyObject_method_imp(
self, _cmd, anObject);
640 [
self didChangeValueForKey:aKey
641 withSetMutation:CPKeyValueMinusSetMutation
642 usingObjects:[CPSet setWithObject:anObject]];
646 if (removeKey_method)
648 var removeKey_method_imp = removeKey_method.method_imp;
650 class_addMethod(KVOClass, removeKey_selector,
function(
self, _cmd, objects)
652 [
self willChangeValueForKey:aKey
653 withSetMutation:CPKeyValueMinusSetMutation
654 usingObjects:[objects copy]];
656 removeKey_method_imp(
self, _cmd, objects);
658 [
self didChangeValueForKey:aKey
659 withSetMutation:CPKeyValueMinusSetMutation
660 usingObjects:[objects copy]];
665 var intersectKey_selector = sel_getUid(
"intersect" + capitalizedKey +
":"),
666 intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
668 if (intersectKey_method)
670 var intersectKey_method_imp = intersectKey_method.method_imp;
672 class_addMethod(KVOClass, intersectKey_selector,
function(
self, _cmd, aSet)
674 [
self willChangeValueForKey:aKey
675 withSetMutation:CPKeyValueIntersectSetMutation
676 usingObjects:[aSet copy]];
678 intersectKey_method_imp(
self, _cmd, aSet);
680 [
self didChangeValueForKey:aKey
681 withSetMutation:CPKeyValueIntersectSetMutation
682 usingObjects:[aSet copy]];
687 var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects],
688 affectingKeysCount = affectingKeys ? affectingKeys.length : 0;
690 if (!affectingKeysCount)
693 var dependentKeysForClass = _nativeClass[DependentKeysKey];
695 if (!dependentKeysForClass)
697 dependentKeysForClass = {};
698 _nativeClass[DependentKeysKey] = dependentKeysForClass;
701 while (affectingKeysCount--)
703 var affectingKey = affectingKeys[affectingKeysCount],
704 affectedKeys = dependentKeysForClass[affectingKey];
708 affectedKeys = [CPSet new];
709 dependentKeysForClass[affectingKey] = affectedKeys;
712 [affectedKeys addObject:aKey];
717 if (affectingKey.indexOf(
@".") !== -1)
718 [_targetObject addObserver:self forKeyPath:affectingKey options:CPKeyValueObservingOptionPrior | kvoNewAndOld context:nil];
720 [
self _replaceModifiersForKey:affectingKey];
724 - (void)observeValueForKeyPath:(
CPString)theKeyPath ofObject:(
id)theObject change:(CPDictionary)theChanges context:(
id)theContext
727 var dependentKeysForClass = _nativeClass[DependentKeysKey],
728 dependantKeys = [dependentKeysForClass[theKeyPath] allObjects],
729 isBeforeFlag = !![theChanges
objectForKey:CPKeyValueChangeNotificationIsPriorKey];
731 for (var i = 0; i < [dependantKeys count]; i++)
733 var dependantKey = [dependantKeys objectAtIndex:i];
734 [
self _sendNotificationsForKey:dependantKey changeOptions:theChanges isBefore:isBeforeFlag];
738 - (void)_addObserver:(
id)anObserver forKeyPath:(
CPString)aPath options:(CPKeyValueObservingOptions)options context:(
id)aContext
745 if (aPath.indexOf(
'.') !==
CPNotFound && aPath.charAt(0) !==
'@')
746 forwarder = [[_CPKVOForwardingObserver alloc] initWithKeyPath:aPath
object:_targetObject observer:anObserver options:options context:aContext];
748 [
self _replaceModifiersForKey:aPath];
750 var observers = _observersForKey[aPath];
755 _observersForKey[aPath] = observers;
756 _observersForKeyLength++;
759 [observers setObject:_CPKVOInfoMake(anObserver, options, aContext, forwarder) forKey:[anObserver UID]];
763 var newValue = [_targetObject valueForKeyPath:aPath];
765 if (newValue === nil || newValue === undefined)
769 [anObserver observeValueForKeyPath:aPath ofObject:_targetObject change:changes context:aContext];
773 - (void)_removeObserver:(
id)anObserver forKeyPath:(
CPString)aPath
775 var observers = _observersForKey[aPath];
781 CPLog.warn(
@"Cannot remove an observer %@ for the key path \"%@\
" from %@ because it is not registered as an observer.", _targetObject, aPath, anObserver);
790 var observer = [observers objectForKey:[anObserver UID]],
791 forwarder = observer ? observer.forwarder : nil;
793 [forwarder finalize];
796 [observers removeObjectForKey:[anObserver UID]];
798 if (![observers count])
800 _observersForKeyLength--;
801 delete _observersForKey[aPath];
804 if (!_observersForKeyLength)
806 _targetObject.isa = _nativeClass;
807 delete _targetObject[KVOProxyKey];
813 - (void)_sendNotificationsForKey:(
CPString)aKey changeOptions:(CPDictionary)changeOptions isBefore:(BOOL)isBefore
815 var changes = _changesForKey[aKey];
822 var level = _nestingForKey[aKey];
827 _nestingForKey[aKey] = level + 1;
832 _nestingForKey[aKey] = 1;
834 changes = changeOptions;
836 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
837 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
841 var setMutationObjects = [changes[_CPKeyValueChangeSetMutationObjectsKey] copy],
842 setExistingObjects = [[_targetObject valueForKey: aKey] copy];
846 [setExistingObjects intersectSet: setMutationObjects];
847 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
851 [setExistingObjects minusSet: setMutationObjects];
852 [changes setValue:setExistingObjects forKey:CPKeyValueChangeOldKey];
858 [setMutationObjects minusSet: setExistingObjects];
861 changes[_CPKeyValueChangeSetMutationNewValueKey] = setMutationObjects;
866 var type = [changes objectForKey:CPKeyValueChangeKindKey];
872 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
873 [changes setValue:newValues forKey:CPKeyValueChangeOldKey];
878 var oldValue = [_targetObject valueForKey:aKey];
880 if (oldValue === nil || oldValue === undefined)
883 [changes setObject:oldValue forKey:CPKeyValueChangeOldKey];
886 [changes setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey];
888 _changesForKey[aKey] = changes;
892 var level = _nestingForKey[aKey];
894 if (!changes || !level)
896 if (_targetObject._willChangeMessageCounter && _targetObject._willChangeMessageCounter[aKey])
899 _targetObject._willChangeMessageCounter[aKey] -= 1;
901 if (!_targetObject._willChangeMessageCounter[aKey])
902 delete _targetObject._willChangeMessageCounter[aKey];
907 [
CPException raise:@"CPKeyValueObservingException"
reason:@"'didChange...' message called without prior call of 'willChange...'"];
910 _nestingForKey[aKey] = level - 1;
919 delete _nestingForKey[aKey];
921 [changes removeObjectForKey:CPKeyValueChangeNotificationIsPriorKey];
923 var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey],
924 setMutationKind = changes[_CPKeyValueChangeSetMutationKindKey];
930 var newValue = changes[_CPKeyValueChangeSetMutationNewValueKey];
931 [changes setValue:newValue forKey:CPKeyValueChangeNewKey];
934 delete changes[_CPKeyValueChangeSetMutationNewValueKey];
935 delete changes[_CPKeyValueChangeSetMutationObjectsKey];
936 delete changes[_CPKeyValueChangeSetMutationKindKey];
940 var type = [changes objectForKey:CPKeyValueChangeKindKey];
946 var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
947 [changes setValue:newValues forKey:CPKeyValueChangeNewKey];
952 var newValue = [_targetObject valueForKey:aKey];
954 if (newValue === nil || newValue === undefined)
957 [changes setObject:newValue forKey:CPKeyValueChangeNewKey];
960 delete _changesForKey[aKey];
963 var observers = [_observersForKey[aKey] allValues],
964 count = observers ? observers.length : 0;
968 var observerInfo = observers[count];
971 [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context];
974 var dependentKeysMap = _nativeClass[DependentKeysKey];
976 if (!dependentKeysMap)
979 var dependentKeyPaths = [dependentKeysMap[aKey] allObjects];
981 if (!dependentKeyPaths)
985 count = [dependentKeyPaths count];
987 for (; index < count; ++index)
989 var keyPath = dependentKeyPaths[index];
991 [
self _sendNotificationsForKey:keyPath
992 changeOptions:isBefore ? [changeOptions
copy] : _changesForKey[keyPath]
998 @implementation _CPKVOModelSubclass :
CPObject
1003 - (void)willChangeValueForKey:(
CPString)aKey
1005 var superClass = [
self class],
1006 methodSelector =
@selector(willChangeValueForKey:),
1007 methodImp = class_getMethodImplementation(superClass, methodSelector);
1009 methodImp(
self, methodSelector, aKey);
1016 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1019 - (void)didChangeValueForKey:(
CPString)aKey
1021 var superClass = [
self class],
1022 methodSelector =
@selector(didChangeValueForKey:),
1023 methodImp = class_getMethodImplementation(superClass, methodSelector);
1025 methodImp(
self, methodSelector, aKey);
1030 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1033 - (void)willChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1035 var superClass = [
self class],
1036 methodSelector =
@selector(willChange:valuesAtIndexes:forKey:),
1037 methodImp = class_getMethodImplementation(superClass, methodSelector);
1039 methodImp(
self, methodSelector, change, indexes, aKey);
1046 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1049 - (void)didChange:(CPKeyValueChange)change valuesAtIndexes:(
CPIndexSet)indexes forKey:(
CPString)aKey
1051 var superClass = [
self class],
1052 methodSelector =
@selector(didChange:valuesAtIndexes:forKey:),
1053 methodImp = class_getMethodImplementation(superClass, methodSelector);
1055 methodImp(
self, methodSelector, change, indexes, aKey);
1060 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1063 - (void)willChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1065 var superClass = [
self class],
1066 methodSelector =
@selector(willChangeValueForKey:withSetMutation:usingObjects:),
1067 methodImp = class_getMethodImplementation(superClass, methodSelector);
1069 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1074 var changeKind = _changeKindForSetMutationKind(mutationKind),
1078 changeOptions[_CPKeyValueChangeSetMutationObjectsKey] = objects;
1079 changeOptions[_CPKeyValueChangeSetMutationKindKey] = mutationKind;
1081 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:changeOptions isBefore:YES];
1084 - (void)didChangeValueForKey:(
CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects
1086 var superClass = [
self class],
1087 methodSelector =
@selector(didChangeValueForKey:withSetMutation:usingObjects:),
1088 methodImp = class_getMethodImplementation(superClass, methodSelector);
1090 methodImp(
self, methodSelector, aKey, mutationKind, objects);
1095 [[_CPKVOProxy proxyForObject:self] _sendNotificationsForKey:aKey changeOptions:nil isBefore:NO];
1100 return self[KVOProxyKey]._nativeClass;
1105 return [[
self class] superclass];
1108 - (BOOL)isKindOfClass:(Class)aClass
1110 return [[
self class] isSubclassOfClass:aClass];
1113 - (BOOL)isMemberOfClass:(Class)aClass
1115 return [
self class] == aClass;
1120 return [
self class].name;
1124 @implementation _CPKVOModelDictionarySubclass :
CPObject
1129 - (void)removeAllObjects
1131 var keys = [
self allKeys],
1132 count = [keys count],
1135 for (; i < count; i++)
1136 [self willChangeValueForKey:keys[i]];
1138 var superClass = [
self class],
1139 methodSelector =
@selector(removeAllObjects),
1140 methodImp = class_getMethodImplementation(superClass, methodSelector);
1142 methodImp(
self, methodSelector);
1144 for (i = 0; i < count; i++)
1145 [self didChangeValueForKey:keys[i]];
1148 - (void)removeObjectForKey:(
id)aKey
1150 [
self willChangeValueForKey:aKey];
1152 var superClass = [
self class],
1153 methodSelector =
@selector(removeObjectForKey:),
1154 methodImp = class_getMethodImplementation(superClass, methodSelector);
1156 methodImp(
self, methodSelector, aKey);
1158 [
self didChangeValueForKey:aKey];
1161 - (void)setObject:(
id)anObject forKey:(
id)aKey
1163 [
self willChangeValueForKey:aKey];
1165 var superClass = [
self class],
1166 methodSelector =
@selector(setObject:forKey:),
1167 methodImp = class_getMethodImplementation(superClass, methodSelector);
1169 methodImp(
self, methodSelector, anObject, aKey);
1171 [
self didChangeValueForKey:aKey];
1176 @implementation _CPKVOForwardingObserver :
CPObject
1189 - (id)initWithKeyPath:(
CPString)aKeyPath object:(
id)anObject observer:(
id)anObserver options:(
unsigned)options context:(
id)aContext
1191 self = [
super init];
1193 _context = aContext;
1194 _observer = anObserver;
1198 var dotIndex = aKeyPath.indexOf(
'.');
1201 [
CPException raise:CPInvalidArgumentException
reason:"Created _CPKVOForwardingObserver without compound key path: " + aKeyPath];
1203 _firstPart = aKeyPath.substring(0, dotIndex);
1204 _secondPart = aKeyPath.substring(dotIndex + 1);
1207 [_object addObserver:self forKeyPath:_firstPart options:_options context:nil];
1210 _value = [_object valueForKey:_firstPart];
1213 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1218 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(CPDictionary)changes context:(
id)aContext
1220 if (aKeyPath === _firstPart)
1222 var oldValue = [_value valueForKeyPath:_secondPart],
1223 newValue = [_object valueForKeyPath:_firstPart + "." + _secondPart],
1230 [_observer observeValueForKeyPath:_firstPart + "." + _secondPart ofObject:_object change:pathChanges context:_context];
1234 [_value removeObserver:self forKeyPath:_secondPart];
1236 _value = [_object valueForKey:_firstPart];
1239 [_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
1244 [_observer observeValueForKeyPath:_firstPart + "." + aKeyPath ofObject:_object change:changes context:_context];
1251 [_value removeObserver:self forKeyPath:_secondPart];
1253 [_object removeObserver:self forKeyPath:_firstPart];
1263 var _CPKVOInfoMake =
function(anObserver, theOptions, aContext, aForwarder)
1266 observer: anObserver,
1267 options: theOptions,
1269 forwarder: aForwarder