【问题标题】:How do I remove instance methods at runtime in Objective-C 2.0?如何在 Objective-C 2.0 的运行时删除实例方法?
【发布时间】:2009-08-22 04:55:04
【问题描述】:

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

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

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

【问题讨论】:

    标签: objective-c runtime


    【解决方案1】:

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

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

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

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

    method_setImplementation(methodToRemove, forwardingIMP);
    

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

    【讨论】:

      【解决方案2】:

      简而言之,你不能。

      您可以在 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

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

      【讨论】:

      • “为什么”的答案是我有兴趣编写一些代码来显示使用 KVC 时会发生什么。通过在运行时添加和删除方法,我可以让用户探索存在各种方法组合的效果。我得出的结论是,唯一能做到这一点的方法就是搞砸内部结构。而Objective-C 2.0 以各种方式阻止了这种情况,除了hackery。
      • 可能有点晚了,但是:也许在您的示例中,您可以在运行时动态创建响应您想要的方法的子类。然后,您可以简单地创建一个没有该方法的基类的新子类,而不是删除一个方法。
      • 另一种需要删除方法的情况:在单元测试中,您有时需要存根现有类中的方法。 OCMock 框架允许您执行此操作,但 OCMock 本身在单个测试后很难恢复类,因为它无法删除方法。它可以用存根替换现有方法的IMP,但是如果方法在父类中,则需要在子类中添加存根,然后无法摆脱它。所以,回应“你想做什么?”问题:我完全得到“自以为是的软件”,但我认为 Apple 的运行时不应该是这样。
      • @ErikDoernenburg 有趣的问题;与其说运行时是固执己见,不如说它专注于性能和稳定性。删除方法需要大量额外的工程努力才能不严重影响性能,同时还要经常做一些事情来证明支持它的努力是合理的。但是,您描述的使用模式显然是有价值的。请提交描述该需求的增强请求(并在此处发布错误号)。
      • 动态子类化和添加您需要的方法并将对象的类更改为该实例怎么样。每次你需要删除一个方法时,重新创建动态子类以使没有被删除的方法。
      猜你喜欢
      • 1970-01-01
      • 2016-02-04
      • 2011-10-27
      • 1970-01-01
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      相关资源
      最近更新 更多