Objective-C之performSelector编译器内存泄露警告
前言
performSelector may cause a leak because its selector is unknown
在ARC
环境下,我们使用-(id)performSelector:
方法时,编译器会提示可能导致内存泄露的警告。大家如果一直使用ARC
进行iOS
开发,没有经历MRC
时期的话,可能心里会有疑问,为什么Apple
提供的API
会报警告呢,又为什么会报内存泄露的警告?接下来,将详细讨论该问题。
原因
其实,产生该问题的原因是ARC
,运行时系统需要知道调用方法的返回值类型,我们知道,方法的返回值包括:void
,int
,NSString *
,id
等,ARC
通常可以通过定义实例方法对象的头中获取信息。
ARC
对于返回值有3种处理情况:
- 忽略非对象类型(
void
,int
等) - 当新建对象值不再需要时
release
(如init
,copy
或带有ns_returns_retained
属性的方法) - 不做任何处理,且假设返回的对象值会在局部作用域内有效(在最里层的
autorelease pool
结束之前都有效)
调用-(id)performSelector:
,编译器会假设调用方法的返回值是一个对象,且不会对返回值进行retain
/release
,所以,如果你调用如上讨论的第2种情况下的方法,将导致内存泄露,因为,调用的方法会返回一个新的对象。
如果#SEL
返回值类型为void
或非对象类型,是可以安全的使用-(id)performSelector:
的。
解决方法
使用编译器指令移除警告。(注意,该方法治标不治本,对于上面讨论的内存泄露情况,仍然存在)
1
2
3
4#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector: NSSelectorFromString(@"someMethod") withObject: nil];
#pragma clang diagnostic pop使用
NSInvocation
封装方法调用。对于返回值为
void
,int
等值类型,可以使用- performSelector:withObject:afterDelay:
来执行,由于它不会在当前RunLoop
时调用,所以会立即返回,且在接下来的某个RunLoop
中执行,也就没有了返回值。也可以使用运行时方法objc_msgSend(self, NSSelectorFromString(@"someMethod"));
。
附录
Swift
已经废弃了-(id)performSelector:
方法。