diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index a4b02c50d..2169e9901 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -26,114 +26,91 @@ @import "CPObject.j" -var CPObjectAccessorsForClass = nil, - CPObjectModifiersForClass = nil; - CPUndefinedKeyException = @"CPUndefinedKeyException"; CPTargetObjectUserInfoKey = @"CPTargetObjectUserInfoKey"; CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; -var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", - CPObjectModifiersForClassKey = @"$CPObjectModifiersForClassKey"; +var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", + CPObjectModifiersForClassKey = @"$CPObjectModifiersForClassKey", + CPObjectInstanceVariablesForClassKey = @"$CPObjectInstanceVariablesForClassKey"; -var Null = [CPNull null]; var _accessorForKey = function(theClass, aKey) { var selector = nil, accessors = theClass[CPObjectAccessorsForClassKey]; - if (accessors) - { - selector = accessors[aKey]; + if (!accessors) + accessors = theClass[CPObjectAccessorsForClassKey] = { }; - if (selector) - return selector === Null ? nil : selector; - } - else - accessors = theClass[CPObjectAccessorsForClassKey] = {}; + else if (accessors.hasOwnProperty(aKey)) + return accessors[aKey]; var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); - if ([theClass instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || - [theClass instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || - [theClass instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || - [theClass instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || //FIXME: is deprecated in Cocoa 10.3 - [theClass instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || //FIXME: is deprecated in Cocoa 10.3 - [theClass instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) //FIXME: was NEVER supported by Cocoa - { - accessors[aKey] = selector; + [theClass instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || + //FIXME: is deprecated in Cocoa 10.3 + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || + //FIXME: is deprecated in Cocoa 10.3 + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || + //FIXME: was NEVER supported by Cocoa + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)] || + (selector = nil); - return selector; - } + accessors[aKey] = selector; - accessors[aKey] = Null; - - return nil; + return selector; } var _modifierForKey = function(theClass, aKey) { - if (!CPObjectModifiersForClass) - CPObjectModifiersForClass = [CPDictionary dictionary]; + var selector = nil, + modifiers = theClass[CPObjectModifiersForClassKey]; - var UID = [theClass UID], - selector = nil, - modifiers = [CPObjectModifiersForClass objectForKey:UID]; + if (!modifiers) + modifiers = theClass[CPObjectModifiersForClassKey] = { }; - if (modifiers) - { - selector = [modifiers objectForKey:aKey]; - - if (selector) - return selector === Null ? nil : selector; - } - else - { - modifiers = [CPDictionary dictionary]; - - [CPObjectModifiersForClass setObject:modifiers forKey:UID]; - } + else if (modifiers.hasOwnProperty(aKey)) + return modifiers[aKey]; var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1) + ':'; - if ([theClass instancesRespondToSelector:selector = CPSelectorFromString("set" + capitalizedKey)] || - [theClass instancesRespondToSelector:selector = CPSelectorFromString("_set" + capitalizedKey)]) //FIXME: deprecated in Cocoa 10.3 - { - [modifiers setObject:selector forKey:aKey]; + [theClass instancesRespondToSelector:selector = CPSelectorFromString("set" + capitalizedKey)] || + //FIXME: deprecated in Cocoa 10.3 + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_set" + capitalizedKey)] || + (selector = nil); - return selector; - } + modifiers[aKey] = selector; - [modifiers setObject:Null forKey:aKey]; - - return nil; + return selector; } -var _ivarForKey = function(theObject, aKey) +var _ivarForKey = function(theClass, aKey) { - var ivar = '_' + aKey; + var variables = theClass[CPObjectInstanceVariablesForClassKey]; - if (typeof theObject[ivar] != "undefined") - return ivar; + if (!variables) + variables = theClass[CPObjectInstanceVariablesForClassKey] = { }; - var isKey = "is" + aKey.charAt(0).toUpperCase() + aKey.substr(1); + else if (variables.hasOwnProperty(aKey)) + return variables[aKey]; - ivar = '_' + isKey; + var name = '_' + aKey; - if (typeof theObject[ivar] != "undefined") - return ivar; + if (!class_getInstanceVariable(theClass, name)) + { + var isKey = "is" + aKey.charAt(0).toUpperCase() + aKey.substr(1); - ivar = aKey; + class_getInstanceVariable(theClass, name = '_' + isKey) || + class_getInstanceVariable(theClass, name = aKey) || + class_getInstanceVariable(theClass, name = isKey) || + (name = nil); + } - if (typeof theObject[ivar] != "undefined") - return ivar; + variables[aKey] = name; - ivar = isKey; - - if (typeof theObject[ivar] != "undefined") - return ivar; - - return nil; + return name; } @implementation CPObject (CPKeyValueCoding) @@ -157,7 +134,7 @@ var _ivarForKey = function(theObject, aKey) if ([theClass accessInstanceVariablesDirectly]) { - var ivar = _ivarForKey(self, aKey); + var ivar = _ivarForKey(theClass, aKey); if (ivar) return self[ivar]; @@ -170,7 +147,7 @@ var _ivarForKey = function(theObject, aKey) { var firstDotIndex = aKeyPath.indexOf("."); - if (firstDotIndex === -1) + if (firstDotIndex === CPNotFound) return [self valueForKey:aKeyPath]; var firstKeyComponent = aKeyPath.substring(0, firstDotIndex), @@ -193,6 +170,7 @@ var _ivarForKey = function(theObject, aKey) if (value === nil) [dictionary setObject:[CPNull null] forKey:key]; + else [dictionary setObject:value forKey:key]; } @@ -209,11 +187,12 @@ var _ivarForKey = function(theObject, aKey) - (void)setValue:(id)aValue forKeyPath:(CPString)aKeyPath { - if (!aKeyPath) aKeyPath = @"self"; + if (!aKeyPath) + aKeyPath = @"self"; var firstDotIndex = aKeyPath.indexOf("."); - if (firstDotIndex === -1) + if (firstDotIndex === CPNotFound) return [self setValue:aValue forKey:aKeyPath]; var firstKeyComponent = aKeyPath.substring(0, firstDotIndex), @@ -233,7 +212,7 @@ var _ivarForKey = function(theObject, aKey) if ([theClass accessInstanceVariablesDirectly]) { - var ivar = _ivarForKey(self, aKey); + var ivar = _ivarForKey(theClass, aKey); if (ivar) { @@ -259,8 +238,10 @@ var _ivarForKey = function(theObject, aKey) while (key = [keyEnumerator nextObject]) { value = [keyedValues objectForKey: key]; + if (value === [CPNull null]) [self setValue: nil forKey: key]; + else [self setValue: value forKey: key]; } @@ -275,7 +256,7 @@ var _ivarForKey = function(theObject, aKey) @end -@implementation CPDictionary (KeyValueCoding) +@implementation CPDictionary (CPKeyValueCoding) - (id)valueForKey:(CPString)aKey { @@ -287,15 +268,16 @@ var _ivarForKey = function(theObject, aKey) - (void)setValue:(id)aValue forKey:(CPString)aKey { - if (aValue) + if (aValue !== nil) [self setObject:aValue forKey:aKey]; + else - [self removeObjectForKey: aKey]; + [self removeObjectForKey:aKey]; } @end -@implementation CPNull (KeyValueCoding) +@implementation CPNull (CPKeyValueCoding) - (id)valueForKey:(CPString)aKey { diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 8fc5ca9ac..a83bf8bd5 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -37,19 +37,19 @@ { } -- (void)willChange:(CPKeyValueChange)change valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)key +- (void)willChange:(CPKeyValueChange)aChange valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)aKey { } -- (void)didChange:(CPKeyValueChange)change valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)key +- (void)didChange:(CPKeyValueChange)aChange valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)aKey { } -- (void)willChangeValueForKey:(CPString)key withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects +- (void)willChangeValueForKey:(CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)aMutationKind usingObjects:(CPSet)objects { } -- (void)didChangeValueForKey:(CPString)key withSetMutation:(CPKeyValueSetMutationKind)mutationKind usingObjects:(CPSet)objects +- (void)didChangeValueForKey:(CPString)aKey withSetMutation:(CPKeyValueSetMutationKind)aMutationKind usingObjects:(CPSet)objects { } @@ -282,18 +282,12 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld, kvoClass._replacedKeys = _replacedKeys; //copy in the methods from our model subclass - var methodList = _CPKVOModelSubclass.method_list; + var methods = class_copyMethodList(_CPKVOModelSubclass); + if ([_targetObject isKindOfClass:[CPDictionary class]]) - methodList = methodList.concat(_CPKVOModelDictionarySubclass.method_list); + methods = methods.concat(class_copyMethodList(_CPKVOModelDictionarySubclass)); - var count = methodList.length, - i = 0; - - for (; i < count; i++) - { - var method = methodList[i]; - class_addMethod(kvoClass, method_getName(method), method_getImplementation(method), ""); - } + class_addMethods(kvoClass, methods); _targetObject.isa = kvoClass; } diff --git a/Objective-J/Runtime.js b/Objective-J/Runtime.js index 1da5c09f4..0d1145d0f 100644 --- a/Objective-J/Runtime.js +++ b/Objective-J/Runtime.js @@ -61,11 +61,12 @@ GLOBAL(objj_class) = function(displayName) this.name = NULL; this.info = 0; - this.ivars = []; + + this.ivar_list = []; + this.ivar_store = function() { }; + this.ivar_dtable = this.ivar_store.prototype; this.method_list = []; - this.method_hash = {}; - this.method_store = function() { }; this.method_dtable = this.method_store.prototype; @@ -135,10 +136,15 @@ GLOBAL(class_addIvar) = function(/*Class*/ aClass, /*String*/ aName, /*String*/ { var thePrototype = aClass.allocator.prototype; + // FIXME: Use getInstanceVariable if (typeof thePrototype[aName] != "undefined") return NO; - aClass.ivars.push(new objj_ivar(aName, aType)); + var ivar = new objj_ivar(aName, aType); + + aClass.ivar_list.push(ivar); + aClass.ivar_dtable[aName] = ivar; + thePrototype[aName] = NULL; return YES; @@ -157,9 +163,12 @@ GLOBAL(class_addIvars) = function(/*Class*/ aClass, /*Array*/ivars) var ivar = ivars[index], name = ivar.name; + // FIXME: Use getInstanceVariable if (typeof thePrototype[name] === "undefined") { - aClass.ivars.push(ivar); + aClass.ivar_list.push(ivar); + aClass.ivar_dtable[name] = ivar; + thePrototype[name] = NULL; } } @@ -169,20 +178,18 @@ DISPLAY_NAME(class_addIvars); GLOBAL(class_copyIvarList) = function(/*Class*/ aClass) { - return aClass.ivars.slice(0); + return aClass.ivar_list.slice(0); } DISPLAY_NAME(class_copyIvarList); -//#define class_copyIvarList(aClass) (aClass.ivars.slice(0)) +//#define class_copyIvarList(aClass) (aClass.ivar_list.slice(0)) #define METHOD_DISPLAY_NAME(aClass, aMethod) (ISMETA(aClass) ? '+' : '-') + " [" + class_getName(aClass) + ' ' + method_getName(aMethod) + ']' GLOBAL(class_addMethod) = function(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anImplementation, /*Array*/ types) { - if (aClass.method_hash[aName]) - return NO; - + // FIXME: return NO if it exists? var method = new objj_method(aName, anImplementation, types); aClass.method_list.push(method); @@ -215,9 +222,7 @@ GLOBAL(class_addMethods) = function(/*Class*/ aClass, /*Array*/ methods) { var method = methods[index]; - if (aClass.method_hash[method.name]) - continue; - + // FIXME: Don't do it if it exists? method_list.push(method); method_dtable[method.name] = method; @@ -246,6 +251,19 @@ GLOBAL(class_getInstanceMethod) = function(/*Class*/ aClass, /*SEL*/ aSelector) DISPLAY_NAME(class_getInstanceMethod); +GLOBAL(class_getInstanceVariable) = function(/*Class*/ aClass, /*String*/ aName) +{ + if (!aClass || !aName) + return NULL; + + // FIXME: this doesn't appropriately deal with Object's properties. + var variable = aClass.ivar_dtable[aName]; + + return variable; +} + +DISPLAY_NAME(class_getInstanceVariable); + GLOBAL(class_getClassMethod) = function(/*Class*/ aClass, /*SEL*/ aSelector) { if (!aClass || !aSelector) @@ -370,12 +388,11 @@ GLOBAL(objj_allocateClassPair) = function(/*Class*/ superclass, /*String*/ aName // Give our current allocator all the instance variables of our super class' allocator. classObject.allocator.prototype = new superclass.allocator; - // "Inheret" parent methods. - classObject.method_store.prototype = new superclass.method_store; - classObject.method_dtable = classObject.method_store.prototype; + // "Inheret" parent properties. + classObject.ivar_dtable = classObject.ivar_store.prototype = new superclass.ivar_store; + classObject.method_dtable = classObject.method_store.prototype = new superclass.method_store; - metaClassObject.method_store.prototype = new superclass.isa.method_store; - metaClassObject.method_dtable = metaClassObject.method_store.prototype; + metaClassObject.method_dtable = metaClassObject.method_store.prototype = new superclass.isa.method_store; // Set up the actual class hierarchy. classObject.super_class = superclass; @@ -456,7 +473,7 @@ class_createInstance = function(/*Class*/ aClass) while (theClass) { - var ivars = theClass.ivars, + var ivars = theClass.ivar_list, count = ivars.length; while (count--)