我得到ARC编译器的以下警告:
"performSelector may cause a leak because its selector is unknown".
这是我正在做的:
[_controller performSelector:NSSelectorFromString(@"someMethod")];
为什么我得到这个警告?我理解编译器不能检查选择器是否存在,但为什么会导致泄漏?我怎样才能改变我的代码,让我不再得到这个警告呢?
我得到ARC编译器的以下警告:
"performSelector may cause a leak because its selector is unknown".
这是我正在做的:
[_controller performSelector:NSSelectorFromString(@"someMethod")];
为什么我得到这个警告?我理解编译器不能检查选择器是否存在,但为什么会导致泄漏?我怎样才能改变我的代码,让我不再得到这个警告呢?
当前回答
下面是基于上面给出的答案更新的宏。这应该允许您使用return语句来包装代码。
#define SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING(code) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
code; \
_Pragma("clang diagnostic pop") \
SUPPRESS_PERFORM_SELECTOR_LEAK_WARNING(
return [_target performSelector:_action withObject:self]
);
其他回答
您还可以在这里使用协议。因此,创建一个这样的协议:
@protocol MyProtocol
-(void)doSomethingWithObject:(id)object;
@end
在需要调用选择器的类中,有一个@属性。
@interface MyObject
@property (strong) id<MyProtocol> source;
@end
当你需要在MyObject的实例中调用@selector(doSomethingWithObject:)时,这样做:
[self.source doSomethingWithObject:object];
为了子孙后代着想,我决定参加竞选:)
最近,我看到越来越多的重构偏离了目标/选择器范式,而倾向于协议、块等。然而,我已经使用过几次的performSelector有一个替代物:
[NSApp sendAction: NSSelectorFromString(@"someMethod") to: _controller from: nil];
这些似乎是一个干净的,弧安全的,和几乎相同的替代performSelector没有太多的objc_msgSend()。
不过,我不知道iOS上是否有类似的功能。
因为您正在使用ARC,所以必须使用iOS 4.0或更高版本。这意味着你可以使用积木。如果不是记住要执行的选择器,而是取一个块,ARC将能够更好地跟踪实际发生的事情,并且不必冒意外引入内存泄漏的风险。
为了让Scott Thompson的宏更通用:
// String expander
#define MY_STRX(X) #X
#define MY_STR(X) MY_STRX(X)
#define MYSilenceWarning(FLAG, MACRO) \
_Pragma("clang diagnostic push") \
_Pragma(MY_STR(clang diagnostic ignored MY_STR(FLAG))) \
MACRO \
_Pragma("clang diagnostic pop")
然后这样使用它:
MYSilenceWarning(-Warc-performSelector-leaks,
[_target performSelector:_action withObject:self];
)
如果你不需要传递任何参数,一个简单的解决方法是使用valueForKeyPath。这甚至可以在Class对象上实现。
NSString *colorName = @"brightPinkColor";
id uicolor = [UIColor class];
if ([uicolor respondsToSelector:NSSelectorFromString(colorName)]){
UIColor *brightPink = [uicolor valueForKeyPath:colorName];
...
}