如何在Objective-C 2.0中在运行时删除实例方法?

时间:2009-08-22 04:55:05

标签: objective-c runtime

是否可以删除使用class_addMethod添加到类的方法?

或者如果我想这样做,我是否必须在运行时使用objc_allocateClassPair继续创建类,并为它们添加不同的方法集来改变实现的方法?

我会接受包含hackery的答案: - )

2 个答案:

答案 0 :(得分:15)

你不能完全“删除”一个方法,但是通过使方法只是将所有内容重定向到消息转发路径​​(最终将调用-forwardInvocation:的代码),你可以获得与删除相同的效果。 。有两种方法可以实现这一目标:

    _objc_msgForward()中声明但未包含在在线文档中的
  1. /usr/include/objc/message.h可用作您尝试删除的方法的IMP。因为它没有文档,所以可能被视为私有或不受支持。
  2. 您可以使用您知道不存在的选择器调用class_getMethodImplementation(),并将结果用作您尝试删除的方法的IMP。根据文档,这应该与第一个选项具有相同的效果:
  3.   

    返回的函数指针可以是运行时内部的函数,而不是实际的方法实现。例如,如果类的实例不响应选择器,则返回的函数指针将成为运行时消息转发机制的一部分。

    在任何一种情况下,都变得如此简单:

    method_setImplementation(methodToRemove, forwardingIMP);
    

    请注意,这将基本上阻止任何超类实现,因此如果任何超类可能具有您想要保留的有效实现,则必须更加小心。在这种情况下,您可以从超类或类似的东西中获取IMP

答案 1 :(得分:10)

简而言之,你不能。

你可以在Objective-C 1.0 ABI / API中通过:

OBJC_EXPORT void class_removeMethods(Class, struct objc_method_list *) OBJC2_UNAVAILABLE;

但是在Objective-C 2.0中删除了该功能,因为删除方法几乎不是正确的答案。当然不足以证明支持所述功能所产生的开销是合理的。

同样从ObjC2.0 ABI中删除了能够直接访问类/方法结构的能力。它们现在是不透明的,以便将来可以更改它们而不会破坏二进制兼容性。

但是,您可以使用自定义代理来改变它响应的方法集。请参阅NSProxy类的文档; http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html

当然,这个问题引出了一个问题“你想做什么?”。这种即时元编程是非典型的。一旦类被实例化,通常认为在假设先前的实例化仍然依赖于所述方法的情况下改变它响应的方法集合是不合适的。