问题描述
我在某种情况下,我想在运行时为一个类动态生成getter和setter(以类似于NSManagedObject在后台的方式)。从我的理解,这是可能使用resolveInstanceMethod:在一个特定的类。此时,您必须使用class_addMethod动态添加基于选择器的方法。我理解这在理论层面,但我没有深入到obj-c运行时,所以我很好奇,如果有任何伟大的例子如何做到这一点。我的大部分知识来自这篇文章:
I am in a situation where I want to dynamically generate getters and setters for a class at runtime (in a similar manner to what NSManagedObject does behind the scenes). From my understanding, this is possible using resolveInstanceMethod: on a specific class. At this point, you would have to use class_addMethod to dynamically add the method based on the selector. I understand this at a theoretical level, but I haven't delved much into the obj-c runtime, so I was curious if there were any great examples of how to do this. Most of my knowledge comes from this article:
任何想法/示例?
推荐答案
Ash的。这不是那么难,实际上。
The only nice discussion I know is at Mike Ash's blog post. It's not that hard, actually.
我曾经需要将一个大的 NSManagedObject 子类拆分为两个,但决定保留实现细节我不必重写我的应用程序的其他部分。所以,我需要合成getter和setter,发送 [self foo] 到 [self.data foo] 。
I once needed to split a big NSManagedObject subclass into two, but decided to keep the fact an implementation detail so that I don't have to rewrite other parts of my app. So, I needed to synthesize getter and setter which sends [self foo] to [self.data foo], automatically.
为此,我做了以下工作:
To achieve that, I did the following:
-
新的方法,已经在我的类。
Prepare the new method, already in my class.
- (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 '
Note that _cmd has the selector in it. So, usually, _cmd is either @selector(_getter_) or @selector(_setter_) in these methods, but I'm going to plug the implementation of _getter_ as the implementation of foo. Then, _cmd contains @selector(foo), and thus calls self.data's 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)); }
注意这是一个类方法。因此 self 代表类。还要注意,我没有硬编码类型编码(这告诉Objective-C运行时特定方法的参数)。类型编码的语法是文档化的,但手工构建非常容易出错;我浪费了几天,直到迈克·艾姆告诉我停止它。
Note that this is a class method. So self stands for the class. Note also that I didn't hardcode type encodings (which tells Objective-C runtime what the arguments of the particular method are). The syntax of type encodings is documented, but constructing by hand is very error-prone; I wasted a few days that way until Mike Ash told me to stop it. Generate it using an existing method.
尽早生成转发器:
+(void)load { for(NSString*selectorName in [NSArray arrayWithObjects:@"foo", @"bar", @"baz",nil]){ [self synthesizeForwarder:selectorName]; } }
这会生成 foo , setFoo:, bar , setBar:和 baz , setBaz:。
希望这有助于!
这篇关于动态Getters和Setter与Objective C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!