Remove dead code, use just in time setter replacement.

Typo fix.

Better way to replace methods, courtesy of Francisco.
This commit is contained in:
Ross Boucher
2009-01-18 16:55:15 -08:00
parent 0559bac7a9
commit 9d34f3d4e6
+41 -94
View File
@@ -24,6 +24,7 @@
@import "CPDictionary.j"
@import "CPException.j"
@import "CPObject.j"
@import "CPSet.j"
@implementation CPObject (KeyValueObserving)
@@ -54,7 +55,7 @@
[[KVOProxyMap objectForKey:[self hash]] _removeObserver:anObserver forKeyPath:aPath];
}
- (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
{
return YES;
}
@@ -89,7 +90,7 @@ var KVOProxyMap = [CPDictionary dictionary];
Class _nativeClass;
CPDictionary _changesForKey;
CPDictionary _observersForKey;
CPDictionary _replacementMethods;
CPSet _replacedKeys;
}
+ (id)proxyForObject:(CPObject)anObject
@@ -101,10 +102,6 @@ var KVOProxyMap = [CPDictionary dictionary];
proxy = [[self alloc] initWithTarget:anObject];
//[proxy _replaceSetters];
//anObject.isa = proxy.isa;
[proxy _replaceClass];
[KVOProxyMap setObject:proxy forKey:[anObject hash]];
@@ -118,55 +115,13 @@ var KVOProxyMap = [CPDictionary dictionary];
_targetObject = aTarget;
_nativeClass = [aTarget class];
_replacementMethods = [CPDictionary dictionary];
_observersForKey = [CPDictionary dictionary];
_changesForKey = [CPDictionary dictionary];
_replacedKeys = [CPSet set];
return self;
}
- (void)_replaceSetters
{
var currentClass = [_targetObject class];
while (currentClass && currentClass != currentClass.super_class)
{
var methodList = currentClass.method_list,
count = methodList.length;
for (var i=0; i<count; i++)
{
var newMethod = _kvoMethodForMethod(_targetObject, methodList[i]);
if (newMethod)
[_replacementMethods setObject:newMethod forKey:methodList[i].name];
}
currentClass = currentClass.super_class;
}
}
- (void)_replaceSetters
{
var currentClass = [_targetObject class];
while (currentClass && currentClass != currentClass.super_class)
{
var methodList = currentClass.method_list,
count = methodList.length;
for (var i=0; i<count; i++)
{
var newMethod = _kvoMethodForMethod(_targetObject, methodList[i]);
if (newMethod)
[_replacementMethods setObject:newMethod forKey:methodList[i].name];
}
currentClass = currentClass.super_class;
}
}
- (void)_replaceClass
{
var currentClass = _nativeClass,
@@ -183,23 +138,8 @@ var KVOProxyMap = [CPDictionary dictionary];
objj_registerClassPair(kvoClass);
_class_initialize(kvoClass);
while (currentClass && currentClass != currentClass.super_class)
{
var methodList = currentClass.method_list,
count = methodList.length;
for (var i=0; i<count; i++)
{
var newMethodImp = _kvoMethodForMethod(_targetObject, methodList[i]);
if (newMethodImp)
class_addMethod(kvoClass, method_getName(methodList[i]), newMethodImp, "");
}
currentClass = currentClass.super_class;
}
//copy in the methods from our model subclass
var methodList = _CPKVOModelSubclass.method_list,
count = methodList.length;
@@ -212,6 +152,33 @@ var KVOProxyMap = [CPDictionary dictionary];
_targetObject.isa = kvoClass;
}
- (void)_replaceSetterForKey:(CPString)aKey
{
if ([_replacedKeys containsObject:aKey] || ![_nativeClass automaticallyNotifiesObserversForKey:aKey])
return;
var currentClass = _nativeClass,
capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1),
replacementMethods = [
"set"+capitalizedKey+":",
"_set"+capitalizedKey+":",
"insertObject:in"+capitalizedKey+"AtIndex:",
"replaceObjectIn"+capitalizedKey+"AtIndex:",
"removeObjectFrom"+capitalizedKey+"AtIndex:"
];
for (var i=0, count=replacementMethods.length; i<count; i++)
{
if ([_nativeClass instancesRespondToSelector:replacementMethods[i]])
{
var theSelector = sel_getName(replacementMethods[i]),
theMethod = class_getInstanceMethod(_nativeClass, theSelector);
class_addMethod(_targetObject.isa, theSelector, _kvoMethodForMethod(aKey, theMethod), "");
}
}
}
- (void)_addObserver:(id)anObserver forKeyPath:(CPString)aPath options:(unsigned)options context:(id)aContext
{
if (!anObserver)
@@ -221,6 +188,8 @@ var KVOProxyMap = [CPDictionary dictionary];
if (aPath.indexOf('.') != CPNotFound)
forwarder = [[_CPKVOForwardingObserver alloc] initWithKeyPath:aPath object:_targetObject observer:anObserver options:options context:aContext];
else
[self _replaceSetterForKey:aPath];
var observers = [_observersForKey objectForKey:aPath];
@@ -448,36 +417,14 @@ var _CPKVOInfoMake = function _CPKVOInfoMake(anObserver, theOptions, aContext, a
};
}
var _kvoKeyForSetter = function _kvoKeyForSetter(selector)
var _kvoMethodForMethod = function _kvoMethodForMethod(theKey, theMethod)
{
if (selector.split(":").length > 2 || !([selector hasPrefix:@"set"] || [selector hasPrefix:@"_set"]))
return nil;
var keyIndex = selector.indexOf("set") + "set".length,
colonIndex = selector.indexOf(":");
return selector.charAt(keyIndex).toLowerCase() + selector.substring(keyIndex+1, colonIndex);
}
var _kvoMethodForMethod = function _kvoMethodForMethod(theObject, theMethod)
{
var methodName = theMethod.name,
methodImplementation = theMethod.method_imp,
setterKey = _kvoKeyForSetter(methodName);
if (setterKey && objj_msgSend(theObject, @selector(automaticallyNotifiesObserversForKey:), setterKey))
{
var newMethodImp = function(self)
{
[self willChangeValueForKey:setterKey];
methodImplementation.apply(self, arguments);
[self didChangeValueForKey:setterKey];
}
return newMethodImp;
return function(self)
{
[self willChangeValueForKey:theKey];
theMethod.method_imp.apply(self, arguments);
[self didChangeValueForKey:theKey];
}
return nil;
}
@implementation CPArray (KeyValueObserving)