Fixed: Method types was not copied into new KVO implementation of a class that is observed with KVO.

Some test cases are also added for this.
This commit is contained in:
Martin Carlberg
2015-11-20 12:43:53 +01:00
parent b132a66707
commit 758ad3eb06
2 changed files with 74 additions and 15 deletions
+13 -13
View File
@@ -423,7 +423,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
setKey_method_imp(self, _cmd, anObject);
[self didChangeValueForKey:aKey];
}, "");
}, setKey_method.method_types);
}
// FIXME: Deprecated.
@@ -441,7 +441,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
_setKey_method_imp(self, _cmd, anObject);
[self didChangeValueForKey:aKey];
}, "");
}, _setKey_method.method_types);
}
// Ordered To-Many Relationships
@@ -478,7 +478,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, "");
}, insertObject_inKeyAtIndex_method.method_types);
}
if (insertKey_atIndexes_method)
@@ -496,7 +496,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeInsertion
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, "");
}, insertKey_atIndexes_method.method_types);
}
if (removeObjectFromKeyAtIndex_method)
@@ -514,7 +514,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, "");
}, removeObjectFromKeyAtIndex_method.method_types);
}
if (removeKeyAtIndexes_method)
@@ -532,7 +532,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeRemoval
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, "");
}, removeKeyAtIndexes_method.method_types);
}
// These are optional.
@@ -558,7 +558,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[CPIndexSet indexSetWithIndex:anIndex]
forKey:aKey];
}, "");
}, replaceObjectInKeyAtIndex_withObject_method.method_types);
}
var replaceKeyAtIndexes_withKey_selector =
@@ -581,7 +581,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChange:CPKeyValueChangeReplacement
valuesAtIndexes:[indexes copy]
forKey:aKey];
}, "");
}, replaceKeyAtIndexes_withKey_method.method_types);
}
}
@@ -615,7 +615,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, "");
}, addKeyObject_method.method_types);
}
if (addKey_method)
@@ -633,7 +633,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueUnionSetMutation
usingObjects:[objects copy]];
}, "");
}, addKey_method.method_types);
}
if (removeKeyObject_method)
@@ -651,7 +651,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[CPSet setWithObject:anObject]];
}, "");
}, removeKeyObject_method.method_types);
}
if (removeKey_method)
@@ -669,7 +669,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueMinusSetMutation
usingObjects:[objects copy]];
}, "");
}, removeKey_method.method_types);
}
// intersect<Key>: is optional.
@@ -691,7 +691,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti
[self didChangeValueForKey:aKey
withSetMutation:CPKeyValueIntersectSetMutation
usingObjects:[aSet copy]];
}, "");
}, intersectKey_method.method_types);
}
}
+61 -2
View File
@@ -28,7 +28,7 @@ var _getCheeseCounter;
count = arguments.length;
for (; index < count; ++index)
class_addMethod(theClass, arguments[index], function() { });
class_addMethod(theClass, arguments[index], function() { }, ["void"]);
return [theClass new];
}
@@ -268,7 +268,8 @@ var _getCheeseCounter;
- (void)testOnlyInsertObject_AtKeyIndex_Implemented
{
var insertSelector = @selector(insertObject:inObjectsAtIndex:),
object = [self objectWithMethods:insertSelector];
object = [self objectWithMethods:insertSelector],
methodTypes = class_getInstanceMethod(object.isa, insertSelector).method_types;
// Sanity check
[self assert:class_getInstanceMethod(object.isa, insertSelector)
@@ -417,6 +418,64 @@ var _getCheeseCounter;
[self assert:test equals:_lastObject];
}
- (void)testMethodTypesOnKVOForSet_Key_Implemented
{
var setSelector = @selector(setObjects:),
object = [self objectWithMethods:setSelector],
methodTypes = class_getInstanceMethod(object.isa, setSelector).method_types;
// Sanity check
[self assert:class_getInstanceMethod(object.isa, setSelector)
same:class_getInstanceMethod([object class], setSelector)];
[object
addObserver:self
forKeyPath:@"objects"
options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew
context:NULL];
// Sanity check
[self assert:class_getInstanceMethod(object.isa, setSelector)
notSame:class_getInstanceMethod([object class], setSelector)];
// Check that the return and parameter types are the same on the new method as the old
[self assertTrue:methodTypes != nil message:@"methodTypes can not be nil or undefined"];
[self assert:methodTypes equals:class_getInstanceMethod(object.isa, setSelector).method_types];
}
- (void)testMethodTypesOnKVOForInsertObject_AtKeyIndex_Implemented_and_removeFromKeyAtIndex
{
var insertSelector = @selector(insertObject:inObjectsAtIndex:),
removeSelector = @selector(removeObjectFromObjectsAtIndex:),
object = [self objectWithMethods:insertSelector, removeSelector],
methodTypesInsert = class_getInstanceMethod(object.isa, insertSelector).method_types,
methodTypesRemove = class_getInstanceMethod(object.isa, removeSelector).method_types;
// Sanity check
[self assert:class_getInstanceMethod(object.isa, insertSelector)
same:class_getInstanceMethod([object class], insertSelector)];
[self assert:class_getInstanceMethod(object.isa, removeSelector)
same:class_getInstanceMethod([object class], removeSelector)];
[object
addObserver:self
forKeyPath:@"objects"
options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew
context:NULL];
// Sanity check
[self assert:class_getInstanceMethod(object.isa, insertSelector)
notSame:class_getInstanceMethod([object class], insertSelector)];
[self assert:class_getInstanceMethod(object.isa, removeSelector)
notSame:class_getInstanceMethod([object class], removeSelector)];
// Check that the return and parameter types are the same on the new method as the old
[self assertTrue:methodTypesInsert != nil message:@"methodTypes can not be nil or undefined on insert selector"];
[self assertTrue:methodTypesRemove != nil message:@"methodTypes can not be nil or undefined in remove selector"];
[self assert:methodTypesInsert equals:class_getInstanceMethod(object.isa, insertSelector).method_types];
[self assert:methodTypesRemove equals:class_getInstanceMethod(object.isa, removeSelector).method_types];
}
@end
@implementation ObservingTester : CPObject