【问题标题】:How do you suppress linker warning when overriding a class instance method in a category覆盖类别中的类实例方法时如何抑制链接器警告
【发布时间】:2013-02-23 23:54:56
【问题描述】:

需要使用类别覆盖方法。我也意识到这样做的危险(这是另一个类中的私有类,没有人会编写另一个覆盖类别方法,因此不能保证未定义的行为)。我见过很多类似的questions,但它们都使用类似这样的方式解决了抑制编译器警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

// do your override

#pragma clang diagnostic pop

但是这仍然会留下 linker 警告。在 Xcode 4.6 中,我认为安全的特定覆盖是否可以摆脱它?

这是一个sample GitHub project 说明问题。

【问题讨论】:

  • 如果您愿意解释为什么需要它,我们或许可以为您提供替代解决方案。您的示例代码没有向我们展示原因,因为在此示例中并不明显,为什么您不使用子类化。
  • @vikingosegundo 我想替换方法实现,同时仍保留对其超类的访问权限(并发现这是一种比方法调配更优雅的方法)。有关更多信息,请参阅此问题:stackoverflow.com/questions/15291390/… 在那个问题中,我要求提供该问题的替代解决方案。在这里,我只是询问如何抑制实际的链接器警告以供将来参考。
  • 我从不认为抑制警告是优雅的。也许它比方法调配更丑……
  • 您为什么认为在您的情况下不会保证未定义的行为?来自Avoid Category Method Name Clashes:在Apple文档中:“如果在一个类别中声明的方法的名称与原始类中的方法相同,...,对于使用哪个方法实现的行为未定义在运行时。”
  • 你可以试试method swizzle

标签: objective-c clang


【解决方案1】:

好的,正如我在评论中解释的那样,您尝试做的事情是危险的,不应该这样做。我还建议阅读runtime documentation 以了解原因并了解实现目标的其他方法。你应该读一下。

在任何情况下,您正在做的另一种方法是使用运行时环境“跳过”初始化层次结构中的一个类,从而有效地“覆盖”超类,从而产生完全相同的结果而不会引发太多危险信号方法。

这是如何完成的一个选项,在您的示例项目中,将 FunkyBranch 类实现更改为:

#import "FunkyBranch.h"
#import <objc/runtime.h>

typedef id(*InitIMP)(id,SEL);

@implementation FunkyBranch

-(id) init
{
    InitIMP superSuperInit = (InitIMP)class_getMethodImplementation([[self superclass] superclass], @selector(init));

    self = superSuperInit(self, @selector(init));
    if (self)
    {
        NSLog(@"FunkyBranch initialized");
    }
    return self;
}

@end

它将与您当前的实施产生相同的结果,而没有您正在做的事情的危险。

请记住,将函数指针转换为正确的类型至关重要,而且我仍然认为您应该重新考虑您的方法,而不是强制运行时执行它不打算执行的操作。无论如何,这回答了你的问题。

【讨论】:

  • FWIW,这是一种非常合理的方式(OP)来覆盖方法,例如用于测试。我们以这种方式覆盖方法来控制它们的实现,使用仅为测试目标加载的类别。 IMO 并没有那么可怕。这是一个巧妙的技巧,虽然有点难以理解。
猜你喜欢
  • 2012-08-03
  • 2013-01-02
  • 1970-01-01
  • 2011-03-25
  • 2019-12-21
  • 2012-03-14
  • 2013-02-01
  • 2019-12-22
  • 1970-01-01
相关资源
最近更新 更多