在项目中遇到使用字符串来创建 选择器,编译时发现警告:"PerformSelector may cause a leak because its selector is unknown"
参考文档:
http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown
http://stackoverflow.com/questions/8773226/performselector-warning
在ARC模式下,运行时需要知道如何处理你正在调用的方法的返回值。这个返回值可以是任意值,如void
,int
,char
,NSString
,id
等等。ARC通导入头文件或者前向声明来获得来函数定义来得到这些信息。所以平时我们用到的静态选择器就不会出现这个警告。因为在编译期间,这些信息都已经确定。
例如AdSupport.framework苹果允许我们调用,否则审核无法通过,这个时候只能通过动态的方案来获取
[ASIdentifierManager sharedManager].advertisingIdentifier.UUIDString 这一句代码只能通过动态的方式来获取
Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager");
if(ASIdentifierManagerClass)
{
SEL sharedManagerSEL = NSSelectorFromString(@"sharedManager");
if([ASIdentifierManagerClass respondsToSelector:sharedManagerSEL])
{
id share = [ASIdentifierManagerClass performSelector:sharedManagerSEL];
SEL advertisingIdentifierSEL = NSSelectorFromString(@"advertisingIdentifier1");
if([share respondsToSelector:advertisingIdentifierSEL])
{
idfa = ((NSUUID*)[share performSelector:advertisingIdentifierSEL]).UUIDString;
}
else
{
idfa = nil;
}
}else
{
idfa = nil;
}
}
else
{
idfa = nil;
}
会出现上面的警告: PerformSelector may cause a leak because its selector is unknown
SEL selector = NSSelectorFromString(@"someMethod");
IMP imp = [_controller methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(_controller, selector);
当有参数时则使用
SEL selector = NSSelectorFromString(@"processRegion:ofView:");
IMP imp = [_controller methodForSelector:selector];
CGRect (*func)(id, SEL, CGRect, UIView *) = (void *)imp;
CGRect result = func(_controller, selector, someRect, someView);
最近在iOS中使用objc_msgSend() 会出现错误信息是:Too many arguments to function call, expected 0, have 3
不能直接使用 objc_msgSend() 方法,需要先定义它的原型方法
解决方案是
选中项目 - Project - Build Settings - ENABLE_STRICT_OBJC_MSGSEND 将其设置为 NO 即可
原型方法: id (*handle)(id,SEL) = (id(*)(id,SEL))objc_msgSend;
id share = handle(ASIdentifierManagerClass,sharedManagerSEL);
缺点:前两个当有时参数有变化,或者接口有变化时,该代码的容错率不高,容易导致崩溃
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id share = [ASIdentifierManagerClass performSelector:sharedManagerSEL];
#pragma clang diagnostic pop
进一步改为宏编译警告:
#define CancelPerformSelectorLeakWarning(Stuff) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
Stuff; \
_Pragma("clang diagnostic pop") \
} while (0)
CancelPerformSelectorLeakWarning(idfa = ((NSUUID*)[share performSelector:advertisingIdentifierSEL]).UUIDString);
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"