RAC中的@weakify和@strongify浅析

  • Post author:
  • Post category:其他


其实如果我们打开Xcode中查看预编译之后宏被替换的结果我们就会发现@weakify(self)被替换成了下面这个

@autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self);

其实如果我们去查看下自己写的解决循环引用的代码,会然后查看下预编译之后的结果其实和上面的是一模一样的,除了你命名的名字不一样

__weak __typeof__(self) weakSelf = self;

其中__weak被替换成了__attribute__((objc_ownership(weak)))


然后我们其实再去看下面的这个@strongify(self)其实也是一样的道理,被替换成了,这里就是

self_weak_赋值给新声明的局部变量self

@autoreleasepool {} __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_;

然后我们点击进入@weakify中进去看会发现这样的内容

#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

首先补充一下_Pragma这个操作符具有与 #pragma 指令相同的功能,在C/C++标准中,#pragma是一条预处理的指令(preprocessor directive)。其实就是#pragma是用来向编译器传达语言标准以外的一些信息,在ios中其实我们会发现如果我们定义了这段代码, #pragma mark – UITableViewDelegate ,我们会看到其实编译器帮我们把代码进行了分块。然后由于#pragma 指令不能被用于宏定义中,因为编译器会将指令中的数字符号(“#”)认为为字符串化运算符 (#)。,由于_Pragma是一个操作符,因此可以被用在宏当中

就好比我们这么使用来消除某些API被废弃的警告

    #pragma clang diagnostic push  
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"  
    //code  
    #pragma clang diagnostic pop  

我们再去点击@strongify我们会发现下面的这些宏定义,下面其实也做了消息什么类型的警告,关于这个我们可以在后面这个链接去看报的Clang警告语义

http://fuckingclangwarnings.com/

#define strongify(...) \
    rac_keywordify \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wshadow\"") \
    metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
    _Pragma("clang diagnostic pop")

其中的rac_keywordify其实就是下面的内容也就是说DEBUG模式下是autoreleasepool而release模式下就是try catch,所以其实我们在使用@weakify和@strongify的@其实代表的就是自动释放池前面的@和@try {} @catch (…) {}前面的@

#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif

为什么要这么设计?分不同的模式下来判断。首先我们看下它官方的解释,其实可以这么理解就是当@try { } @catch(…) {}被添加到了前面。在这种情况下,Xcode 本身的错误提示能力能被抑制了,也就是说其实抑制了编译器对返回类型的警告,作用其实就是

不让编译器产生warnings。下面也有说使用@try/@catch来避免产生不必要的释放池

// Details about the choice of backing keyword:
//
// The use of @try/@catch/@finally can cause the compiler to suppress
// return-type warnings.
// The use of @autoreleasepool {} is not optimized away by the compiler,
// resulting in superfluous creation of autorelease pools.
//
// Since neither option is perfect, and with no other alternatives, the
// compromise is to use @autorelease in DEBUG builds to maintain compiler
// analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary
// autorelease pools.



版权声明:本文为ZCMUCZX原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。