mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-15 11:13:50 +00:00
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:
1 parent
f67fafdb8e
commit
ae5d31746e
2 files changed
+276
-253
No files matched your search
+260
-253
@@ -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:),
|
||||
|
||||
Reference in new issue
Block a user