具有Objective C的动态Getter和setter

dtu*_*net 2 cocoa objective-c ios

我处于这样一种情况,我想在运行时为类动态生成getter和setter(与NSManagedObject在幕后的方式类似).根据我的理解,这可以使用resolveInstanceMethod:在特定的类上.此时,您必须使用class_addMethod根据选择器动态添加方法.我在理论层面上理解这一点,但我没有深入研究obj-c运行时,所以我很好奇是否有任何关于如何做到这一点的很好的例子.我的大部分知识都来自这篇文章:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html

有什么想法/例子吗?

Yuj*_*uji 9

我所知道的唯一不错的讨论是Mike Ash的博客文章.实际上,这并不难.

我曾经需要将一个大的NSManagedObject子类分成两个,但决定将事实保留为实现细节,以便我不必重写我的应用程序的其他部分.所以,我需要自动合成发送[self foo]到的getter和setter [self.data foo].

为此,我做了以下事情:

  1. 准备新方法,已经在我的课堂上.

    - (id)_getter_
    {
        return objc_msgSend(self.data, _cmd);
    }
    
    - (void)_setter_:(id)value 
    {
        objc_msgSend(self.data, _cmd,value);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,其中_cmd包含选择器.所以,通常_cmd@selector(_getter_)或者@selector(_setter_)在这些方法中,但是我将插入实现_getter_作为实现foo.然后,_cmd包含@selector(foo),因此调用self.datafoo.

  2. 写一个通用的合成方法:

    +(void)synthesizeForwarder:(NSString*)getterName
    {
        NSString*setterName=[NSString stringWithFormat:@"set%@%@:",
              [[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
        Method getter=class_getInstanceMethod(self, @selector(_getter_));
        class_addMethod(self, NSSelectorFromString(getterName), 
                        method_getImplementation(getter), method_getTypeEncoding(getter));
        Method setter=class_getInstanceMethod(self, @selector(_setter_:));
        class_addMethod(self, NSSelectorFromString(setterName), 
                        method_getImplementation(setter), method_getTypeEncoding(setter));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,这是一种类方法.所以self代表全班.另请注意,我没有硬编码类型编码(它告诉Objective-C运行时特定方法的参数是什么).记录类型编码的语法,但手工构建非常容易出错; 我浪费了几天,直到Mike Ash告诉我阻止它.使用现有方法生成它.

  3. 尽早生成转发器:

     +(void)load  
     {
         for(NSString*selectorName in [NSArray arrayWithObjects:@"foo", @"bar", @"baz",nil]){
            [self synthesizeForwarder:selectorName];
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)

    这会产生foo,setFoo:,bar,setBar:,和baz,setBaz:.

希望这可以帮助!


Dav*_*ong 5

另一个例子是我写的,叫做DynamicStorage,可在这里找到:

https://github.com/davedelong/Demos

它背后的主要推动力是这个问题,它询问如何使用a NSMutableDictionary作为任何对象的后备存储器.我编写了一个类,它将为任何@property事件生成getter和setter ,尊重自定义getter/setter名称,对象内存管理策略等等.关于它的巧妙之处在于它正在使用imp_implementationWithBlock()它以便它只需要计算适当的属性命名一次(然后捕获并将其保存为块的一部分).