Dependent key paths use a relationship (#2431)

Fixed: When dependent key paths use a relationship, only the first added observer will observe the attribute for the relationship object.

Also, an optimisation on when the willChange… chain is running, there is no need to replace the observers as no new values are set yet. That will be done when the didChange… chain is running.
This commit is contained in:
Martin Carlberg authored and cacaodev committed 2016-05-09 22:14:20 +02:00
1 parent f67fafdb8e
commit ae5d31746e
2 files changed
+276 -253

No files matched your search

+260 -253
View File
@@ -399,299 +399,299 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
- (void)_replaceModifiersForKey:(CPString)aKey
{
if ([_replacedKeys containsObject:aKey] || ![_nativeClass automaticallyNotifiesObserversForKey:aKey])
return;
[_replacedKeys addObject:aKey];
var theClass = _nativeClass,
KVOClass = _targetObject.isa,
capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
// Attribute and To-One Relationships
var setKey_selector = sel_getUid("set" + capitalizedKey + ":"),
setKey_method = class_getInstanceMethod(theClass, setKey_selector);
if (setKey_method)
if (![_replacedKeys containsObject:aKey] && [_nativeClass automaticallyNotifiesObserversForKey:aKey])
{
var setKey_method_imp = setKey_method.method_imp;
[_replacedKeys addObject:aKey];
class_addMethod(KVOClass, setKey_selector, function(self, _cmd, anObject)
var theClass = _nativeClass,
KVOClass = _targetObject.isa,
capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
// Attribute and To-One Relationships
var setKey_selector = sel_getUid("set" + capitalizedKey + ":"),
setKey_method = class_getInstanceMethod(theClass, setKey_selector);
if (setKey_method)
{
[self willChangeValueForKey:aKey];
var setKey_method_imp = setKey_method.method_imp;
setKey_method_imp(self, _cmd, anObject);
[self didChangeValueForKey:aKey];
}, setKey_method.method_types);
}
// FIXME: Deprecated.
var _setKey_selector = sel_getUid("_set" + capitalizedKey + ":"),
_setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
if (_setKey_method)
{
var _setKey_method_imp = _setKey_method.method_imp;
class_addMethod(KVOClass, _setKey_selector, function(self, _cmd, anObject)
{
[self willChangeValueForKey:aKey];
_setKey_method_imp(self, _cmd, anObject);
[self didChangeValueForKey:aKey];
}, _setKey_method.method_types);
}
// Ordered To-Many Relationships
var insertObject_inKeyAtIndex_selector = sel_getUid("insertObject:in" + capitalizedKey + "AtIndex:"),
insertObject_inKeyAtIndex_method =
class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
insertKey_atIndexes_selector = sel_getUid("insert" + capitalizedKey + ":atIndexes:"),
insertKey_atIndexes_method =
class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
removeObjectFromKeyAtIndex_selector = sel_getUid("removeObjectFrom" + capitalizedKey + "AtIndex:"),
removeObjectFromKeyAtIndex_method =
class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
removeKeyAtIndexes_selector = sel_getUid("remove" + capitalizedKey + "AtIndexes:"),
removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
(removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
{
if (insertObject_inKeyAtIndex_method)
{
var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector, function(self, _cmd, anObject, anIndex)
class_addMethod(KVOClass, setKey_selector, function(self, _cmd, anObject)
{
[self willChange:CPKeyValueChangeInsertion
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
[self willChangeValueForKey:aKey];
insertObject_inKeyAtIndex_method_imp(self, _cmd, anObject, anIndex);
setKey_method_imp(self, _cmd, anObject);
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, insertObject_inKeyAtIndex_method.method_types);
[self didChangeValueForKey:aKey];
}, setKey_method.method_types);
}
if (insertKey_atIndexes_method)
// FIXME: Deprecated.
var _setKey_selector = sel_getUid("_set" + capitalizedKey + ":"),
_setKey_method = class_getInstanceMethod(theClass, _setKey_selector);
if (_setKey_method)
{
var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
var _setKey_method_imp = _setKey_method.method_imp;
class_addMethod(KVOClass, insertKey_atIndexes_selector, function(self, _cmd, objects, indexes)
class_addMethod(KVOClass, _setKey_selector, function(self, _cmd, anObject)
{
[self willChange:CPKeyValueChangeInsertion
valuesAtIndexes:[indexes copy]
forKey:aKey];
[self willChangeValueForKey:aKey];
insertKey_atIndexes_method_imp(self, _cmd, objects, indexes);
_setKey_method_imp(self, _cmd, anObject);
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, insertKey_atIndexes_method.method_types);
[self didChangeValueForKey:aKey];
}, _setKey_method.method_types);
}
if (removeObjectFromKeyAtIndex_method)
// Ordered To-Many Relationships
var insertObject_inKeyAtIndex_selector = sel_getUid("insertObject:in" + capitalizedKey + "AtIndex:"),
insertObject_inKeyAtIndex_method =
class_getInstanceMethod(theClass, insertObject_inKeyAtIndex_selector),
insertKey_atIndexes_selector = sel_getUid("insert" + capitalizedKey + ":atIndexes:"),
insertKey_atIndexes_method =
class_getInstanceMethod(theClass, insertKey_atIndexes_selector),
removeObjectFromKeyAtIndex_selector = sel_getUid("removeObjectFrom" + capitalizedKey + "AtIndex:"),
removeObjectFromKeyAtIndex_method =
class_getInstanceMethod(theClass, removeObjectFromKeyAtIndex_selector),
removeKeyAtIndexes_selector = sel_getUid("remove" + capitalizedKey + "AtIndexes:"),
removeKeyAtIndexes_method = class_getInstanceMethod(theClass, removeKeyAtIndexes_selector);
if ((insertObject_inKeyAtIndex_method || insertKey_atIndexes_method) &&
(removeObjectFromKeyAtIndex_method || removeKeyAtIndexes_method))
{
var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector, function(self, _cmd, anIndex)
if (insertObject_inKeyAtIndex_method)
{
[self willChange:CPKeyValueChangeRemoval
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
var insertObject_inKeyAtIndex_method_imp = insertObject_inKeyAtIndex_method.method_imp;
removeObjectFromKeyAtIndex_method_imp(self, _cmd, anIndex);
class_addMethod(KVOClass, insertObject_inKeyAtIndex_selector, function(self, _cmd, anObject, anIndex)
{
[self willChange:CPKeyValueChangeInsertion
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, removeObjectFromKeyAtIndex_method.method_types);
insertObject_inKeyAtIndex_method_imp(self, _cmd, anObject, anIndex);
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, insertObject_inKeyAtIndex_method.method_types);
}
if (insertKey_atIndexes_method)
{
var insertKey_atIndexes_method_imp = insertKey_atIndexes_method.method_imp;
class_addMethod(KVOClass, insertKey_atIndexes_selector, function(self, _cmd, objects, indexes)
{
[self willChange:CPKeyValueChangeInsertion
valuesAtIndexes:[indexes copy]
forKey:aKey];
insertKey_atIndexes_method_imp(self, _cmd, objects, indexes);
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, insertKey_atIndexes_method.method_types);
}
if (removeObjectFromKeyAtIndex_method)
{
var removeObjectFromKeyAtIndex_method_imp = removeObjectFromKeyAtIndex_method.method_imp;
class_addMethod(KVOClass, removeObjectFromKeyAtIndex_selector, function(self, _cmd, anIndex)
{
[self willChange:CPKeyValueChangeRemoval
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
removeObjectFromKeyAtIndex_method_imp(self, _cmd, anIndex);
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, removeObjectFromKeyAtIndex_method.method_types);
}
if (removeKeyAtIndexes_method)
{
var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
class_addMethod(KVOClass, removeKeyAtIndexes_selector, function(self, _cmd, indexes)
{
[self willChange:CPKeyValueChangeRemoval
valuesAtIndexes:[indexes copy]
forKey:aKey];
removeKeyAtIndexes_method_imp(self, _cmd, indexes);
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, removeKeyAtIndexes_method.method_types);
}
// These are optional.
var replaceObjectInKeyAtIndex_withObject_selector =
sel_getUid("replaceObjectIn" + capitalizedKey + "AtIndex:withObject:"),
replaceObjectInKeyAtIndex_withObject_method =
class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
if (replaceObjectInKeyAtIndex_withObject_method)
{
var replaceObjectInKeyAtIndex_withObject_method_imp =
replaceObjectInKeyAtIndex_withObject_method.method_imp;
class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
function(self, _cmd, anIndex, anObject)
{
[self willChange:CPKeyValueChangeReplacement
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
replaceObjectInKeyAtIndex_withObject_method_imp(self, _cmd, anIndex, anObject);
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, replaceObjectInKeyAtIndex_withObject_method.method_types);
}
var replaceKeyAtIndexes_withKey_selector =
sel_getUid("replace" + capitalizedKey + "AtIndexes:with" + capitalizedKey + ":"),
replaceKeyAtIndexes_withKey_method =
class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
if (replaceKeyAtIndexes_withKey_method)
{
var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector, function(self, _cmd, indexes, objects)
{
[self willChange:CPKeyValueChangeReplacement
valuesAtIndexes:[indexes copy]
forKey:aKey];
replaceObjectInKeyAtIndex_withObject_method_imp(self, _cmd, indexes, objects);
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, replaceKeyAtIndexes_withKey_method.method_types);
}
}
if (removeKeyAtIndexes_method)
// Unordered To-Many Relationships
var addKeyObject_selector = sel_getUid("add" + capitalizedKey + "Object:"),
addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
addKey_selector = sel_getUid("add" + capitalizedKey + ":"),
addKey_method = class_getInstanceMethod(theClass, addKey_selector),
removeKeyObject_selector = sel_getUid("remove" + capitalizedKey + "Object:"),
removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
removeKey_selector = sel_getUid("remove" + capitalizedKey + ":"),
removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
{
var removeKeyAtIndexes_method_imp = removeKeyAtIndexes_method.method_imp;
class_addMethod(KVOClass, removeKeyAtIndexes_selector, function(self, _cmd, indexes)
if (addKeyObject_method)
{
[self willChange:CPKeyValueChangeRemoval
valuesAtIndexes:[indexes copy]
forKey:aKey];
var addKeyObject_method_imp = addKeyObject_method.method_imp;
removeKeyAtIndexes_method_imp(self, _cmd, indexes);
class_addMethod(KVOClass, addKeyObject_selector, function(self, _cmd, anObject)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[CPSet setWithObject:anObject]];
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, removeKeyAtIndexes_method.method_types);
}
addKeyObject_method_imp(self, _cmd, anObject);
// These are optional.
var replaceObjectInKeyAtIndex_withObject_selector =
sel_getUid("replaceObjectIn" + capitalizedKey + "AtIndex:withObject:"),
replaceObjectInKeyAtIndex_withObject_method =
class_getInstanceMethod(theClass, replaceObjectInKeyAtIndex_withObject_selector);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, addKeyObject_method.method_types);
}
if (replaceObjectInKeyAtIndex_withObject_method)
{
var replaceObjectInKeyAtIndex_withObject_method_imp =
replaceObjectInKeyAtIndex_withObject_method.method_imp;
class_addMethod(KVOClass, replaceObjectInKeyAtIndex_withObject_selector,
function(self, _cmd, anIndex, anObject)
if (addKey_method)
{
[self willChange:CPKeyValueChangeReplacement
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
var addKey_method_imp = addKey_method.method_imp;
replaceObjectInKeyAtIndex_withObject_method_imp(self, _cmd, anIndex, anObject);
class_addMethod(KVOClass, addKey_selector, function(self, _cmd, objects)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[objects copy]];
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, replaceObjectInKeyAtIndex_withObject_method.method_types);
}
addKey_method_imp(self, _cmd, objects);
var replaceKeyAtIndexes_withKey_selector =
sel_getUid("replace" + capitalizedKey + "AtIndexes:with" + capitalizedKey + ":"),
replaceKeyAtIndexes_withKey_method =
class_getInstanceMethod(theClass, replaceKeyAtIndexes_withKey_selector);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[objects copy]];
}, addKey_method.method_types);
}
if (replaceKeyAtIndexes_withKey_method)
{
var replaceKeyAtIndexes_withKey_method_imp = replaceKeyAtIndexes_withKey_method.method_imp;
class_addMethod(KVOClass, replaceKeyAtIndexes_withKey_selector, function(self, _cmd, indexes, objects)
if (removeKeyObject_method)
{
[self willChange:CPKeyValueChangeReplacement
valuesAtIndexes:[indexes copy]
forKey:aKey];
var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
replaceObjectInKeyAtIndex_withObject_method_imp(self, _cmd, indexes, objects);
class_addMethod(KVOClass, removeKeyObject_selector, function(self, _cmd, anObject)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[CPSet setWithObject:anObject]];
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, replaceKeyAtIndexes_withKey_method.method_types);
}
}
removeKeyObject_method_imp(self, _cmd, anObject);
// Unordered To-Many Relationships
var addKeyObject_selector = sel_getUid("add" + capitalizedKey + "Object:"),
addKeyObject_method = class_getInstanceMethod(theClass, addKeyObject_selector),
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, removeKeyObject_method.method_types);
}
addKey_selector = sel_getUid("add" + capitalizedKey + ":"),
addKey_method = class_getInstanceMethod(theClass, addKey_selector),
removeKeyObject_selector = sel_getUid("remove" + capitalizedKey + "Object:"),
removeKeyObject_method = class_getInstanceMethod(theClass, removeKeyObject_selector),
removeKey_selector = sel_getUid("remove" + capitalizedKey + ":"),
removeKey_method = class_getInstanceMethod(theClass, removeKey_selector);
if ((addKeyObject_method || addKey_method) && (removeKeyObject_method || removeKey_method))
{
if (addKeyObject_method)
{
var addKeyObject_method_imp = addKeyObject_method.method_imp;
class_addMethod(KVOClass, addKeyObject_selector, function(self, _cmd, anObject)
if (removeKey_method)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[CPSet setWithObject:anObject]];
var removeKey_method_imp = removeKey_method.method_imp;
addKeyObject_method_imp(self, _cmd, anObject);
class_addMethod(KVOClass, removeKey_selector, function(self, _cmd, objects)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[objects copy]];
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, addKeyObject_method.method_types);
}
removeKey_method_imp(self, _cmd, objects);
if (addKey_method)
{
var addKey_method_imp = addKey_method.method_imp;
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[objects copy]];
}, removeKey_method.method_types);
}
class_addMethod(KVOClass, addKey_selector, function(self, _cmd, objects)
// intersect<Key>: is optional.
var intersectKey_selector = sel_getUid("intersect" + capitalizedKey + ":"),
intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
if (intersectKey_method)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[objects copy]];
var intersectKey_method_imp = intersectKey_method.method_imp;
addKey_method_imp(self, _cmd, objects);
class_addMethod(KVOClass, intersectKey_selector, function(self, _cmd, aSet)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueIntersectSetMutation
usingObjects:[aSet copy]];
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[objects copy]];
}, addKey_method.method_types);
}
intersectKey_method_imp(self, _cmd, aSet);
if (removeKeyObject_method)
{
var removeKeyObject_method_imp = removeKeyObject_method.method_imp;
class_addMethod(KVOClass, removeKeyObject_selector, function(self, _cmd, anObject)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[CPSet setWithObject:anObject]];
removeKeyObject_method_imp(self, _cmd, anObject);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, removeKeyObject_method.method_types);
}
if (removeKey_method)
{
var removeKey_method_imp = removeKey_method.method_imp;
class_addMethod(KVOClass, removeKey_selector, function(self, _cmd, objects)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[objects copy]];
removeKey_method_imp(self, _cmd, objects);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[objects copy]];
}, removeKey_method.method_types);
}
// intersect<Key>: is optional.
var intersectKey_selector = sel_getUid("intersect" + capitalizedKey + ":"),
intersectKey_method = class_getInstanceMethod(theClass, intersectKey_selector);
if (intersectKey_method)
{
var intersectKey_method_imp = intersectKey_method.method_imp;
class_addMethod(KVOClass, intersectKey_selector, function(self, _cmd, aSet)
{
[self willChangeValueForKey:aKey
withSetMutation:CPKeyValueIntersectSetMutation
usingObjects:[aSet copy]];
intersectKey_method_imp(self, _cmd, aSet);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueIntersectSetMutation
usingObjects:[aSet copy]];
}, intersectKey_method.method_types);
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueIntersectSetMutation
usingObjects:[aSet copy]];
}, intersectKey_method.method_types);
}
}
}
@@ -1300,6 +1300,10 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
if (aKeyPath === _firstPart)
{
var pathChanges = [CPMutableDictionary dictionaryWithObject:CPKeyValueChangeSetting forKey:CPKeyValueChangeKindKey];
var isBeforeFlag = !![changes objectForKey:CPKeyValueChangeNotificationIsPriorKey];
if (isBeforeFlag)
[pathChanges setObject:1 forKey:CPKeyValueChangeNotificationIsPriorKey];
if (_options & CPKeyValueObservingOptionOld)
{
@@ -1308,7 +1312,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[pathChanges setObject:oldValue != null ? oldValue : [CPNull null] forKey:CPKeyValueChangeOldKey];
}
if (_options & CPKeyValueObservingOptionNew)
if (!isBeforeFlag && (_options & CPKeyValueObservingOptionNew))
{
var newValue = [_object valueForKeyPath:_firstPart + "." + _secondPart];
@@ -1317,14 +1321,17 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[_observer observeValueForKeyPath:_firstPart + "." + _secondPart ofObject:_object change:pathChanges context:_context];
//since a has changed, we should remove ourselves as an observer of the old a, and observe the new one
if (_value)
[_value removeObserver:self forKeyPath:_secondPart];
// Nothing has changed yet when doing willChange....
if (!isBeforeFlag) {
//since a has changed, we should remove ourselves as an observer of the old a, and observe the new one
if (_value)
[_value removeObserver:self forKeyPath:_secondPart];
_value = [_object valueForKey:_firstPart];
_value = [_object valueForKey:_firstPart];
if (_value)
[_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
if (_value)
[_value addObserver:self forKeyPath:_secondPart options:_options context:nil];
}
}
else
{
@@ -265,6 +265,22 @@ var _getCheeseCounter;
[self assert:dependantKeyPathTester equals:_lastObject];
}
- (void)testSendNotificationsForMultipleDependantKeyPathsToTheSameObject
{
var observingTester = [ObservingTester testerWithCheese:@"cheese"],
dependantKeyPathTester = [DependantKeyPathsTester testerWithObservingTester:observingTester],
anotherDependantKeyPathTester = [DependantKeyPathsTester testerWithObservingTester:observingTester];
[dependantKeyPathTester addObserver:self forKeyPath:@"observedCheese" options:CPKeyValueObservingOptionNew context:nil];
[anotherDependantKeyPathTester addObserver:self forKeyPath:@"observedCheese" options:CPKeyValueObservingOptionNew context:nil];
[observingTester setCheese:@"changed cheese"];
[self assert:@"observedCheese" equals:_lastKeyPath];
[self assert:@"observedCheese" equals:_secondLastKeyPath];
[self assertTrue:[[dependantKeyPathTester, anotherDependantKeyPathTester] containsObject:_lastObject] message:@"Last observed object must be one of the DependantKeyPathsTester"];
[self assertTrue:[[dependantKeyPathTester, anotherDependantKeyPathTester] containsObject:_secondLastObject] message:@"Second last observed object must be one of the DependantKeyPathsTester"];
}
- (void)testOnlyInsertObject_AtKeyIndex_Implemented
{
var insertSelector = @selector(insertObject:inObjectsAtIndex:),