我正在使用一个旧的应用程序,并将其内存处理转换为ARC(自动引用计数),并且在我的一个类中,我收到以下警告: PerformSelector可能会导致泄漏,因为其选择器未知。正如 wbyoung 所解释的那样,我研究了这个问题并发现了出色的find。为了减轻警告,我将原始代码从以下位置更改:
- (void)launchExecution {
@autoreleasepool {
// Start executing the requested task
[targetForExecution performSelector:methodForExecution withObject:objectForExecution]; //--WARNING happens here...
// Task completed, update view in main thread (note: view operations should
// be done only in the main thread)
[self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
}
}
我将其修改为:
- (void)launchExecution {
@autoreleasepool {
if(!targetForExecution) return;
SEL selector = methodForExecution;
IMP imp = [targetForExecution methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(targetForExecution, selector);
// Task completed, update view in main thread (note: view operations should
// be done only in the main thread)
[self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
}
}
现在我的问题是这样的:虽然它没有给我任何错误(是的!),但我仍然必须将 ObjectForExecution 值传递到此新配置中。怎么做?我知道有一些变通方法,人们已使用编译指示来忽略此类警告,但我想适当地解决此警告。
答案 0 :(得分:2)
我只会直接使用objc_msgSend
,就像这样:
// At top of file:
#import <objc/message.h>
// To send the message:
((void (*)(id, SEL, id))objc_msgSend)(targetForExecution, methodForExecution, objectForExecution);
请注意,该方法实际返回void
很重要。如果返回一个对象,则该对象可能会泄漏。如果返回struct
,则此代码将崩溃。但是,如果该方法返回void
,则不会泄漏任何内容,并且调用不会崩溃。
答案 1 :(得分:2)
您应将targetForExecution
,methodForExecution
和objectForExecution
替换为block并使用GCD:
- (void)launchExecution {
blockForExecution();
dispatch_async(dispatch_get_main_queue(), ^{
[self cleanUp];
});
}