[IOS development] - @ weakify, @ strongify analytical principle

A long preface

In block statement block, if desired reference self, and self object and the object holding block, it will cause a circular reference 循环引用(retain cycle), leading to memory leaks, such as the following code

  self.block = ^{
    [self description];
};

Generally, we are so resolved, the use of a __weakmodified weakSelf variable points to self object, use weakSelf in the block:

 __weak typeof(self) weakSelf = self;
self.block = ^{
    [weakSelf description];
};

But Jiang Zi write, or may be a problem, because weakSelf is weak references, and self once released, weakSelf may be nil, or give it chestnuts: 1. define a TestObj objects, he had a block of property Object

@interface TestObj : NSObject
@property (nonatomic, copy)void(^block)();
@end

@implementation TestObj
- (void)dealloc {
NSLog(@"%s",__func__);
}
- (instancetype)init {
self = [super init];
if (self) {
    __weak typeof(self) weakSelf = self;
    self.block = ^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"%@",weakSelf);
        });
    };
}
return self;
}

@end

2. yet another instance of the class the method is defined in a testFunc

- (void)testFunc{
TestObj *obj = [TestObj new];
obj.block();

}

Execution testFuncmethod, the result is printed is (null), because the method block in print, in asynchronous execution NSLog(@"%@",weakSelf);before the execution of this code testFuncfunction is over, so the objobject has been the release. How to solve it? So again weakSelfdo once __strongon it:

__weak typeof(self) weakSelf = self;
    self.block = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"%@",strongSelf);
        });
    };
}

Used __strongbefore dispatch_async inside the block of code execution is completed, to selfhave a reference to prevent objects (self) before being released. The scope is over, strongSelfdoes not exist, the object (self) will be released, you can look at specific before I wrote this article .

1. Problem

Although the precise wording of the front, but also solve the problem, but as a program ape like lazy, will not feel very long-winded? Each had to write that two long __weakand __strong, in the block and in the use of self strongSelf all we wanted to change, assuming that the period of a lot of self copy the code block, the one into strongSelf is not very boring ?

2.RAC is how to solve

@weakify(self);
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
@strongify(self);
[self popViewControllerAnimated:YES];
}];

As long as the external block @weakify (self); then write in block @strongify (self); on it, @ strongify (self); self after the statement can be left intact, seems to be the magic, take a look at the following @ weakify, @ strongify both macro magical eventually replace something. RAC introduced header file, replacing the above test code into @weakify (self) using the RAC; and @strongify (self), the Xcode split-screen display, so that the right side of the display content to preprocess ", you can see macro final result of the substitution.

2791393-9eec71afc106cd91.png
image.png
  1. @autoreleasepool {} What the hell?

Notice (self) @ front @weakify the color orange is not no? @Not part of the macro, of course, no reason you can not write @ for it, so the RAC weakify wit macro definitions to give you added a sentence autoreleasepool {}this way, it becomes a front of the losers did not dry @autoreleasepool {}

  1. attribute ((objc_ownership (weak))) What is a ghost?

    This is __weak before being replaced compiler to compile the results, and weakify eventually replace the macro code contains __weak (comes back), so the compiler then replace in that attribute ((objc_ownership (weak)))

2.weakify, strongify definition

Preliminaries

  1. ...with __VA_ARGS__

Look NSLogand printfthey have more incoming parameters, with ... represents the number of uncertain parameters, NSLog look at the definition of: NSLog(NSString *format, ...)the macros can also be used ...to represent multiple parameters, and __VA_ARGS__on a number of parameters corresponding to part . For example, do you think NSLog too difficult to see, want to build their own log a print function, such as Zlog you can write:#define Zlog(...) NSLog(__VA_ARGS__)

  1. Macro connector ##:

##This symbol will appear ##something both sides connected together, for example: as a macro definition #define XLink(n) x ## n, this means that the macro x n, and connects the incoming write:

#define XLink(n) x ## n
int x1 = 1;
int x2 = 2;
int x3 = 3;
//打印x1 x2 x3
NSLog(@"%d",XLink(1)); //NSlog(@"%zd",x1);
NSLog(@"%d",XLink(2)); //NSlog(@"%zd",x2);
NSLog(@"%d",XLink(3)); //NSlog(@"%zd",x3);

Layers of expanded weakify

Suppose we write @weakify (self) what happened to the first layer:

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

rac_keywordifyIn fact, autoreleasepool {}the macro substitution and VA_ARGS is the corresponding parameter we pass here we can become like this:

autoreleasepool {} 
metamacro_foreach_cxt(rac_weakify_,, __weak, self)

Second floor:

#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
 metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

This layer is more magic starts, the substitution result of the first layer becomes so:

autoreleasepool {}
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(self))(rac_weakify_,  , __weak, self)

We look at metamacro_argcount(self)this part, metamacro_argcount(...)this macro is very powerful, can replace the variable parameters (...) number: For example metamacro_argcount (@ "obj")> will be replaced 1metamacro_argcount (@ "obj", @ "obj ")> will be replaced 2so metamacro_argcount (self)> will be replaced 1(only one parameter) and then look at the definition of metamacro_concat:

#define metamacro_concat(A, B) \
 metamacro_concat_(A, B)

Actually also a package, well, then go in and see metamacro_concat_ point definition

#define metamacro_concat_(A, B) A ## B

Ah, So now comes before the macro is connector ##so metamacro_concat (A, B) is the A, B are connected into AB 1, then metamacro_concat metamacro_argcount connection according to the above analysis (self)>:

autoreleasepool {}
metamacro_foreach_cxt ## 1 (rac_weakify_,  , __weak, self)

That is:

autoreleasepool {}
metamacro_foreach_cxt1(rac_weakify_,  , __weak, self)

Third layer: metamacro_foreach_cxt1Yes, do not doubt, he also defines metamacro_foreach_cxt1 behind this array is a macro, search:

2791393-40f7832dab9390a6.png
image.png

Ah, you guessed it, there metamacro_foreach_cxt1 there metamacro_foreach_cxt2,3,4,5,6,7,8 ..., which is what the hell, let's not care, look at our metamacro_foreach_cxt1

#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

Alternatively analysis result of the second layer:

autoreleasepool {}
rac_weakify_(0,__weak,self)    

The amount, it seems clear up, do not hesitate to see how rac_weakify This macro is defined:

#define rac_weakify_(INDEX, CONTEXT, VAR) \
 CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

Replace once again: __weak __typeof__(self) self ## _weak_ = selfthe ultimate truth becomes:

autoreleasepool {}__weak __typeof__(self) self_weak_ = self

Similarly strongify (self) This macro is a final deployment, pay attention to where he redefined the self, in block inside a block of statements is allowed so dry, followed by self is the beginning of a strongSelf article using the same.

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

Pants off you give me this Some people ask why not just use rac_weakify_ like, do less complex spare a large circle, it's not loaded to force it -? - in fact, spare a large circle function is @ weakify (...); can support up to 20 parameters such as: @weakify (ob1, obj2 ..., obj20); eventually replaced by:

@autoreleasepool {}
__weak type(obj1) obj1_weak_ = obj1;
__weak type(obj2) obj2_weak_ = obj2;
...
__weak type(obj20) obj20_weak_ = obj20;

Now, let's talk about how RAC is loaded to force.

3.RAC loaded to force the macro

The definition of metamacro_argcount

He said before metamacro_argcount This macro can be replaced with a variable number of arguments parameters ... to see his definition:

#define metamacro_argcount(...) \
 metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

Look ignorant force? It does not matter, we look at layers: Suppose: metamacro_at (self) becomes: metamacro_at (20, self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8 , 7, 6, 5, 4, 3, 2, 1)

Look at the definition of metamacro_at

#define metamacro_at(N, ...) \
 metamacro_concat(metamacro_at, N)(__VA_ARGS__)

Is replaced into

metamacro_concat(metamacro_at, 20)(self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

Before already know metamacro_concatis to connect the macro, it becomes

metamacro_at20(self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

search formetamacro_at20

2791393-079783e06aedc3e6.png
image.png

Oh is a bunch of garbage, nothing to read a whole understand.

#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) 
metamacro_head(__VA_ARGS__)

Ah, meaning of this macro is to remove the incoming parameters 前20个parameters, the 剩下的parameters passed metamacro_head macros, 20 parameters before metamacro_at20 above is: self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2So the rest of the argument is the 1assumption that a start is not metamacro_at (self) but two or more What argument would happen? For example metamacro_at (self, self)? According to the above rule replaced, they will become

metamacro_at20(self,self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

Remove the front of the 20 parameters, leaving only 2,1 to 2,1 So these two parameters passed metamacro_head(2,1)to see the metamacro_headdefinition

#define metamacro_head(...) \
 metamacro_head_(__VA_ARGS__, 0)

Are next, continue to point into metamacro_head_

#define metamacro_head_(FIRST, ...) FIRST

In fact, the interception of the first argument, so metamacro_head (2,1) is 2. The front metamacro_head (1) is 1. Here I believe you have to figure out how metamacro_at is replaced by a number of parameters

Other metamacro_at also a reason

The definition of metamacro_foreach_cxt

Looking back metamacro_foreach_cxt

#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
 metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
 SEP \
 MACRO(1, CONTEXT, _1)

#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
 metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
 SEP \
 MACRO(2, CONTEXT, _2)
...省略N多行

Back to the beginning, for example metamacro_argcount (obj1, obj2, obj3) by the above metamacro_argcount macro parameter is determined after 3, condemnation incoming metamacro_foreach_cxt3

#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
 metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
 SEP \
 MACRO(2, CONTEXT, _2)

So it became

metamacro_foreach_cxt3(rac_weakify_, , __weak , obj1 ,obj2 ,obj3)

Found to be recursive, that is,

metamacro_foreach_cxt2(rac_weakify_, , CONTEXT, obj1, obj2) 
rac_weakify_(2, __weak, obj3)

The metamacro_foreach_cxt2 is a layer of recursion, and finally obj1, obj2, obj3 have been replaced:

__weak type(obj1) obj1_weak_ = obj1;
__weak type(obj2) obj2_weak_ = obj2;
__weak type(obj3) obj3_weak_ = obj3;

RAC macros loaded to force procedure summary

In fact, sum up very simple, 2 points:

  1. Determining a variable number of arguments by metamacro_argcountx
  2. 1 according to the obtained xcall metamacro_foreach_cxt x, recursive layers, each parameter macro replacement

This article quoted from here , if infringement, please contact me to delete!

Guess you like

Origin blog.csdn.net/weixin_34387284/article/details/90848846