代码之家  ›  专栏  ›  技术社区  ›  Steve Weller

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

  •  10
  • Steve Weller  · 技术社区  · 15 年前

    是否可以用类addmethod删除添加到类中的方法?

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

    我接受包括黑客在内的答案:—)

    2 回复  |  直到 13 年前
        1
  •  10
  •   bbum    15 年前

    简而言之,你不能。

    您可以通过以下方式在目标C 1.0 ABI/API中:

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

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

    从objc2.0abi中还删除了直接访问类/方法结构的能力。它们现在是不透明的,因此将来可以在不破坏二进制兼容性的情况下进行更改。

    不过,您可以做的是使用一个定制代理,它可以改变它响应的一组方法。参见nsproxy类的文档; http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html

    当然,这个问题引出了一个问题“你想做什么?”这样的动态元编程是不典型的。一旦一个类被实例化了,通常不认为需要在先前的实例化可能仍然依赖于所述方法的假设下更改它响应的一组方法。

        2
  •  13
  •   Justin Spahr-Summers    13 年前

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

    1. _objc_msgForward() ,宣布 /usr/include/objc/message.h 但不包括在联机文档中,可以用作 IMP 对于您要删除的方法。因为它是非法的,所以可能被认为是私有的或不受支持的。
    2. 你可以打电话 class_getMethodImplementation() 使用您知道不存在的选择器,并将结果用作 进口 用于要删除的方法。根据文档,这应该与第一个选项具有相同的效果:

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

    无论是哪种情况,它都变得简单如下:

    method_setImplementation(methodToRemove, forwardingIMP);
    

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