"performSelector may cause a leak because its selector is unknown"警告原因及其解决办法

问题: 

      在项目中遇到使用字符串来创建 选择器,编译时发现警告:"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

 1.使用函数指针

    SEL selector = NSSelectorFromString(@"someMethod");

    IMP imp = [_controller methodForSelector:selector];

    void (*func)(idSEL) = (void *)imp;

    func(_controller, selector);

 当有参数时则使用

    SEL selector = NSSelectorFromString(@"processRegion:ofView:");

    IMP imp = [_controller methodForSelector:selector];

    CGRect (*func)(idSEL, CGRect, UIView *) = (void *)imp;

    CGRect result = func(_controller, selector, someRect, someView);

2.使用objc_msgSend()

   最近在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);

缺点:前两个当有时参数有变化,或者接口有变化时,该代码的容错率不高,容易导致崩溃

3.对于上面的代码使用clang编译警告

    #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);


4.在build setting中进行如下设置


5.全局的使用这个宏 

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

你可能感兴趣的:(iOS)