在运行时动态实现委托 [英] Dynamically implementing a delegate during runtime

查看:57
本文介绍了在运行时动态实现委托的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的课堂上,我有一个 UIViewController 的引用,并希望在运行时在这个 ViewController 上实现一个委托.委托只有一个方法(有两个参数),当 ViewController 上的委托方法被调用时,我的类应该处理调用.

In my class, I have a reference on an UIViewController and want to implement a delegate on this ViewController during runtime. The delegate has only one method (with two parameters) and when the delegate-method on the ViewController is invoked, my class should handle the call.

我很确定这可以通过某种方法 swizzling 等实现,但我不知道如何实现.

I am quite sure this is possible with some kind of method swizzling, etc. but I don't know how to accomplish this.

推荐答案

你想要的是可能的,但这不是方法混搭,因为你不想切换到方法而是添加一个新的方法.由于 Objective-C 的动态特性,它可以完成,但它仍然是一个肮脏的黑客,因此还需要向库供应商提交功能请求.

What you want is possible, but it's not method swizzling, since you don't want to switch to methods but add a new one. It can be done, thanks to Objective-C's dynamic nature, but it's still a dirty hack so also file a feature request with the library vendor.

你想要的是class_addMethod() 和一个带有实际实现的 C 函数.还有一件事,Objective-C 方法 C 方法,但是有两个隐式参数,self_cmd,必须记住(无论是在创建 C 方法时还是在告诉 class_addMethod 你的方法签名时.这是一个关于如何关闭类似内容的 SSCE:

What you want is class_addMethod() and a C function with the actual implementation for that. One more thing, Objective-C methods are C methods, but with two implicit parameters, self and _cmd, which have to keep in mind (both when creating your C method and when telling class_addMethod your methods signature. And here is an SSCE of how to pull something like that off:

#import <Foundation/Foundation.h>
#import <objc/runtime.h> // Required for class_addMethod()

@interface MyClass : NSObject
@end

@implementation MyClass
@end


@protocol MyProtocol <NSObject>
- (void)printString:(NSString *)string;
@end




// Note the method signature containing the
// two implicit parameters self and _cmd!
void MyClassPrinStringIMP(id self, SEL _cmd, NSString *string)
{
    NSLog(@"Hi I'm %@:%s and this is the string: %@", self, sel_getName(_cmd), string);
}


void PimpMyClass()
{
    // The last argument is the signature. First character is the return type, in our case void
    // Then comes self and _cmd, followed by the NSString. You can use @encode() to find out how your
    // type is encoded. Best is to build this string at runtime, since the encoding can change with architectures
    class_addMethod([MyClass class], @selector(printString:), (IMP)MyClassPrinStringIMP, "v@:@");
}



int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        PimpMyClass();

        id foo = [[MyClass alloc] init]; // id, to silence the compiler!
        [foo printString:@"Hello World"];
    }

    return 0;
}

示例输出:

Hi I'm <MyClass: 0x100101810>:printString: and this is the string: Hello World

您可能会发现在运行时检查传递的对象是否符合协议或不使用conformsToProtocol:.由于这段代码只是添加了方法实现,它仍然会失败,但是您可以告诉运行时您完全通过这个函数调用实现了该协议:

Something that you may find is that the passed object is checked at runtime wether it conforms to a protocol or not using conformsToProtocol:. Since this code just adds the method implementation, it would still fail, but you can tell the runtime that you totally do implement that protocol with this one function call:

class_addProtocol([MyClass class], @protocol(MyProtocol));

替代方案:代理

Objective-Cs 的动态性和消息转发已经受到@JasperBlues 的称赞,但是,Objective-C 中有一个特定的类就是为了做到这一点:NSProxy.它旨在拦截发送的消息并将它们动态分派到相关目标,并使用高级 NSInvocation 方法.如果您可以以某种方式将代理对象作为委托传递(取决于您的代码允许什么和不允许什么),创建 NSProxy 子类可能是最干净的方法.

Alternative: proxies

Objective-Cs dynamism and message forwarding is already praised by @JasperBlues, however, there is one particular class in Objective-C that is designed to do just that: NSProxy. It is designed to intercept sent messages and dispatching them dynamically to the relevant target, and does use the high-level NSInvocation approach. If you can pass a proxied object in some way as the delegate (depending on what your code allows for and what not), creating a NSProxy subclass might be the cleanest way to go.

但是,请注意,您最终会得到一个包含其他对象的 shim 对象,该对象带有自己的痛苦,并且在您尝试通过 -> 直接访问变量时会中断代码> 语法.它不是一个完全不可见的代理,但对于大多数情况来说已经足够了.

However, note though that you then end up with a shim object that wraps over your other object, which comes with its own bag of pain and will break when you try to directly access variables via -> syntax. It's not a perfectly invisible proxy, but good enough for most cases.

这篇关于在运行时动态实现委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆