代码之家  ›  专栏  ›  技术社区  ›  Amy Worrall

在Cocoa中编写自己的@dynamic属性

  •  16
  • Amy Worrall  · 技术社区  · 14 年前

    假设(为了论证)我有一个视图类,其中包含一个NSDictionary。我想要一大堆属性,所有这些属性都可以访问字典的成员。

    例如,我想要 @property NSString* title @property NSString* author

    对于这些属性中的每一个,实现都是相同的:对于getter,调用 [dictionary objectForKey:propertyName]; ,对于setter,对设置对象:forKey:.

    编写所有这些方法需要大量的时间和大量的复制粘贴代码。有没有一种方法可以像核心数据对NSManagedObject子类的@dynamic properties那样自动生成它们?要清楚的是,我只想通过这种方式访问我在头中定义的属性,而不仅仅是任何任意键。

    我需要这些显式属性,以便在Interface Builder中绑定到它们:我最终计划为此视图编写IB调色板。

    (顺便说一句,我知道我用NSDictionary存储这些的例子有点做作。实际上,我正在编写WebView的一个子类,属性将引用HTML元素的ID,但这对于我的问题的逻辑并不重要!)

    5 回复  |  直到 14 年前
        1
  •  17
  •   Amy Worrall    14 年前

    在仔细阅读了objective-c运行时文档之后,我自己设法解决了这个问题。

    我实现了这个类方法:

    + (BOOL) resolveInstanceMethod:(SEL)aSEL
    {
        NSString *method = NSStringFromSelector(aSEL);
    
        if ([method hasPrefix:@"set"])
        {
            class_addMethod([self class], aSEL, (IMP) accessorSetter, "v@:@");
            return YES;
        }
        else
        {
            class_addMethod([self class], aSEL, (IMP) accessorGetter, "@@:");
            return YES;
        }
        return [super resolveInstanceMethod:aSEL];
    }
    

    NSString* accessorGetter(id self, SEL _cmd)
    {
        NSString *method = NSStringFromSelector(_cmd);
        // Return the value of whatever key based on the method name
    }
    
    void accessorSetter(id self, SEL _cmd, NSString* newValue)
    {
        NSString *method = NSStringFromSelector(_cmd);
    
        // remove set
        NSString *anID = [[[method stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""] lowercaseString] stringByReplacingOccurrencesOfString:@":" withString:@""];
    
        // Set value of the key anID to newValue
    }
    

    由于此代码尝试实现在类上调用但尚未实现的任何方法,因此如果有人尝试调用您期望的对象,则会导致问题。我计划添加一些健全的检查,以确保名称符合我的期望。

        2
  •  2
  •   Max Seelemann    14 年前

    • 使用@dynamic关键字
    • 覆盖valueForKey:和设置值:forKey:访问字典
    • 使用objective-c反射API的方法类\u getProperty并检查它是否为nil。如果不是零,你的类就有这样的属性。如果是的话就没有了。

    我希望这有帮助。可能看起来有点黑客(使用反射),但实际上这是一个非常灵活,也是绝对“合法”的解决方案的问题。。。

    注:核心数据的方式是可能的,但在你的情况下,将是完全杀伤力过大。。。

        3
  •  2
  •   Stephen Furlani    14 年前

    和宏交朋友?这可能不是100%正确。

    #define propertyForKey(key, type) \
        - (void) set##key: (type) key; \
        - (type) key;
    
    #define synthesizeForKey(key, type) \
        - (void) set##key: (type) key \
        { \
             [dictionary setObject];// or whatever \
        } \
        - (type) key { return [dictionary objectForKey: key]; }
    
        4
  •  0
  •   mariachi    14 年前

    听起来你应该用类而不是字典。你已经接近用手来实现语言想要给你的东西了。