gta*_*rga 8 dynamic objective-c objective-c-runtime resolve
我正在尝试编写一些动态代码,用户可以尝试从类的特定实例调用方法,并在运行时解析它.检索信息的实现存在,但访问它的方法不存在,因为它基于每个实例.
例如,用户可能想要调用类中不存在的名为"getSomething"的方法:
[someInstance getSomething]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我希望有一个实现已解析,它具有一个仅适用于正在处理的实例的变量返回类型.我正在考虑使用Objective-C中的class_addMethod,但我并不是100%肯定它的行为.在文档中,它声称这可以用于添加类或实例方法.调用此类是否仅将方法添加到特定实例或类中,以便之后创建的每个实例都将具有该方法?我还读到,一旦添加了一个方法,你就无法删除它.
也许我的方法不正确,所以如果知道任何替代方案我会很感激.我不能使用消息转发,因为没有类可以理解已经实现的选择器.
另一种方法是使用动态子类:
- (void)addCustomMethodToObject:(id)object {
Class objectClass = object_getClass(object);
SEL selectorToOverride = ...; // this is the method name you want to override
NSString *newClassName = [NSString stringWithFormat:@"Custom_%@", NSStringFromClass(objectClass)];
Class c = NSClassFromString(newClassName);
if (c == nil) {
// this class doesn't exist; create it
// allocate a new class
c = objc_allocateClassPair(objectClass, [newClassName UTF8String], 0);
// get the info on the method we're going to override
Method m = class_getInstanceMethod(objectClass, selectorToOverride);
// add the method to the new class
class_addMethod(c, selectorToOverride, (IMP)myCustomFunction, method_getTypeEncoding(m));
// register the new class with the runtime
objc_registerClassPair(c);
}
// change the class of the object
object_setClass(object, c);
}
id myCustomFunction(id self, SEL _cmd, [other params...]) {
// this is the body of the instance-specific method
// you may call super to invoke the original implementation
}
Run Code Online (Sandbox Code Playgroud)
执行此操作后,只会object收到重写的方法,因为它将是唯一的特殊类的实例.此外,此代码仅覆盖实例方法,但修改它以覆盖类方法并不困难.
一如既往,通常的警告:
objc_allocateClassPair()不能用ARC编译.我不熟悉 class_addMethod,但这也许可以帮助您澄清:
请记住,在 Objective-C 中,您并不是在“调用方法”,而是实际上在发送消息。因此,在任何实例化对象上执行 [anyObject anyMethodName] 是安全的。该对象可能会也可能不会响应该消息。
您可以使用 [anyObject respondsToSelector:@selector(@"anyMethodName")] 检查来检查对象是否愿意,如果是,则继续执行 [anyObject anyMethodName] 调用。我无法完全理解您的问题描述,但听起来您有一个充满对象的异构容器,这些对象可能会也可能不会响应调用。在 Objective-C 中,对容器中的每个对象进行“respondsToSelector:”检查是完全正常的事情,听起来像是很好的设计
如果每个对象返回某种不同类型的数据,您可以使用“id”泛型类型来处理。即 id returnData = [anyObject anyMethodName]; 然后,您可以对 returnData 使用内省,或者您可以根据“anyObject”的类进行不同的处理,由 [anyObject class] 检查;
所以就像,
if([anyObject class] == MyGreatClass) // recast data to MyGreatClassCoolReturnType
我希望这有助于回答这个问题