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 __weak
modified 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 testFunc
method, the result is printed is (null), because the method block in print, in asynchronous execution NSLog(@"%@",weakSelf);
before the execution of this code testFunc
function is over, so the obj
object has been the release. How to solve it? So again weakSelf
do once __strong
on 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 __strong
before dispatch_async inside the block of code execution is completed, to self
have a reference to prevent objects (self) before being released. The scope is over, strongSelf
does 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 __weak
and __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.
- @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 {}
-
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
-
...
with__VA_ARGS__
Look NSLog
and printf
they 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__)
- 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_keywordify
In 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 1
metamacro_argcount (@ "obj", @ "obj ")> will be replaced 2
so 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_cxt1
Yes, do not doubt, he also defines metamacro_foreach_cxt1 behind this array is a macro, search:
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_ = self
the 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_concat
is 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
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, 2
So the rest of the argument is the 1
assumption 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_head
definition
#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:
- Determining a variable number of arguments by metamacro_argcount
x
- 1 according to the obtained
x
call metamacro_foreach_cxtx
, recursive layers, each parameter macro replacement
This article quoted from here , if infringement, please contact me to delete!