我得到ARC编译器的以下警告:

"performSelector may cause a leak because its selector is unknown".

这是我正在做的:

[_controller performSelector:NSSelectorFromString(@"someMethod")];

为什么我得到这个警告?我理解编译器不能检查选择器是否存在,但为什么会导致泄漏?我怎样才能改变我的代码,让我不再得到这个警告呢?


当前回答

为了子孙后代着想,我决定参加竞选:)

最近,我看到越来越多的重构偏离了目标/选择器范式,而倾向于协议、块等。然而,我已经使用过几次的performSelector有一个替代物:

[NSApp sendAction: NSSelectorFromString(@"someMethod") to: _controller from: nil];

这些似乎是一个干净的,弧安全的,和几乎相同的替代performSelector没有太多的objc_msgSend()。

不过,我不知道iOS上是否有类似的功能。

其他回答

在项目生成设置中,在其他警告标志(WARNING_CFLAGS)下添加 -Wno-arc-performSelector-leaks

现在只需确保所调用的选择器不会导致对象被保留或复制。

为了子孙后代着想,我决定参加竞选:)

最近,我看到越来越多的重构偏离了目标/选择器范式,而倾向于协议、块等。然而,我已经使用过几次的performSelector有一个替代物:

[NSApp sendAction: NSSelectorFromString(@"someMethod") to: _controller from: nil];

这些似乎是一个干净的,弧安全的,和几乎相同的替代performSelector没有太多的objc_msgSend()。

不过,我不知道iOS上是否有类似的功能。

因为您正在使用ARC,所以必须使用iOS 4.0或更高版本。这意味着你可以使用积木。如果不是记住要执行的选择器,而是取一个块,ARC将能够更好地跟踪实际发生的事情,并且不必冒意外引入内存泄漏的风险。

如果你不需要传递任何参数,一个简单的解决方法是使用valueForKeyPath。这甚至可以在Class对象上实现。

NSString *colorName = @"brightPinkColor";
id uicolor = [UIColor class];
if ([uicolor respondsToSelector:NSSelectorFromString(colorName)]){
    UIColor *brightPink = [uicolor valueForKeyPath:colorName];
    ...
}

在Xcode 4.2的LLVM 3.0编译器中,你可以像下面这样抑制警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self.ticketTarget performSelector: self.ticketAction withObject: self];
#pragma clang diagnostic pop

如果你在几个地方得到错误,并且想要使用C宏系统来隐藏指令,你可以定义一个宏来更容易地抑制警告:

#define SuppressPerformSelectorLeakWarning(Stuff) \
    do { \
        _Pragma("clang diagnostic push") \
        _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
        Stuff; \
        _Pragma("clang diagnostic pop") \
    } while (0)

你可以像这样使用宏:

SuppressPerformSelectorLeakWarning(
    [_target performSelector:_action withObject:self]
);

如果你需要执行消息的结果,你可以这样做:

id result;
SuppressPerformSelectorLeakWarning(
    result = [_target performSelector:_action withObject:self]
);