我处于这样一种情况,我想在运行时动态生成类的getter和setter(与NSManagedObject在幕后的方式类似)。根据我的理解,这可以使用resolveInstanceMethod:在特定的类上。此时,您必须使用class_addMethod根据选择器动态添加方法。我在理论层面上理解这一点,但我没有深入研究obj-c运行时,所以我很好奇是否有任何关于如何做到这一点的很好的例子。我的大部分知识来自这篇文章:
有什么想法/例子吗?
答案 0 :(得分:9)
我所知道的唯一好讨论是Mike Ash的blog post。实际上,这并不难。
我曾经需要将一个大的NSManagedObject
子类拆分为两个,但我决定将这个事实保留为实现细节,这样我就不必重写我应用的其他部分了。所以,我需要合成getter和setter,它会自动将[self foo]
发送到[self.data foo]
。
为实现这一目标,我做了以下事情:
准备新方法,已在我班上。
- (id)_getter_
{
return objc_msgSend(self.data, _cmd);
}
- (void)_setter_:(id)value
{
objc_msgSend(self.data, _cmd,value);
}
请注意_cmd
中有选择器。因此,在这些方法中,_cmd
通常是@selector(_getter_)
或@selector(_setter_)
,但我要将_getter_
的实现作为foo
的实现插入。然后,_cmd
包含@selector(foo)
,因此会调用self.data
的{{1}}。
编写通用的合成方法:
foo
请注意,这是一种类方法。所以+(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));
}
代表班级。另请注意,我没有硬编码类型编码(它告诉Objective-C运行时特定方法的参数是什么)。记录类型编码的语法,但手工构建非常容易出错;我浪费了几天,直到Mike Ash告诉我阻止它。使用现有方法生成它。
尽早生成转发器:
self
这会生成 +(void)load
{
for(NSString*selectorName in [NSArray arrayWithObjects:@"foo", @"bar", @"baz",nil]){
[self synthesizeForwarder:selectorName];
}
}
,foo
,setFoo:
,bar
和setBar:
,baz
。
希望这有帮助!
答案 1 :(得分:5)
另一个例子是我写的一个名为DynamicStorage
的例子,可以在这里找到:
https://github.com/davedelong/Demos
它背后的主要推动力是this question,它询问如何使用NSMutableDictionary
作为任何对象ivar的后备存储。我写了一个类,它将为任何@property
生成getter和setter,尊重自定义getter / setter名称,对象内存管理策略等等。关于它的巧妙之处在于它正在使用imp_implementationWithBlock()
这样它只需要计算一次适当的属性名称(然后捕获并将其保存为块的一部分)。