前言
小時候家長和老師都教導我們,做人要善良要懂得吃虧.長大以后,才知道這樣真的不好,有的時候你越是忍讓越是糟糕,難受的是自己,有一句話說的很好:草木有本心,何須美人折? 活出自己最重要!
草木有本心,何須美人折.JPG
一丶Block儲存的三種類型
1._NSConcretStackBlock(棧)
當block在函數內部,且定義的時候就使用了函數內部的變量,那么這個 block是存儲在棧上的。
typedef void (^Block)(void);
- (void)setUp {
int val = 0;
Block block = ^(){
NSLog(@"val = %d",val);
};
block();
}
2._NSConcretGlobalBlock(全局)
當block定義在函數體外面,或者定義在函數體內部且當時函數執行的時候,block體中并沒有需要使用函數內部的局部變量時,也就是block在函數執行的時候只是靜靜地待在一邊定義了一下而不使用函數體的內容,那么block將會被編譯器存儲為全局block(代碼段)。
typedef void (^Block)(void);
Block block;
- (void)setUp{
block = ^(){
int val = 0
NSLog(@"val = %d",val);
};
}
3._NSConcretMallocBlock(堆)
全局block存儲在堆中,對全局block使用copy操作會返回原函數指針;而對棧中的block使用copy操作,會產生兩個不同的block地址,也就是兩個匿名函數的入口地址。
typedef void (^Block)(void);
@property (nonatomic, copy) Block block;//流經實例ID
self.block = ^(){
int val = 0
NSLog(@"val = %d",val);
};
self.block();
還有注意一下這點:
ARC機制優化會將stack的block,轉為heap的block進行調用。也就是說在ARC環境下,你聲明的block變量,無論用copy或是strong修飾,系統都會幫你把block復制到堆上.
二丶在Block里面修改普通外部變量
block其實是由四個結構體組裝而成,用的不多,這里不多說,感興趣的可以去研究一下源碼.鏈接
我覺得block和一個函數差不多,都是一個代碼塊,等待被調用.
首先
NSString *str;
str 是個普通變量,儲存在棧上,當函數走完以后,就會銷毀.所以當block調用時已經找不到這個變量.
解決方法:
__block NSString *str;
這樣寫的話__block,會生成另外一個結構體,str引用計數加一.
三丶Block的循環引用
解決辦法下面兩個宏:
@weakify(self); // 定義了一個__weak的self_weak_變量
[RACObserve(self, name) subscribeNext:^(NSString *name) {
@strongify(self); // 局域定義了一個__strong的self指針指向self_weak
self.outputLabel.text = name;
}];
宏的實現
#define weakify(...) \\
autoreleasepool {} \\
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
#define strongify(...) \\
try {} @finally {} \\
_Pragma("clang diagnostic push") \\
_Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \\
_Pragma("clang diagnostic pop")
簡單來說:
__weak typeof(self) weakSelf = self;
self.Button.rac_command = [[RACCommand alloc] initWithEnabled:textSig signalBlock:^RACSignal *(NSString * input) {
__strong typeof(weakSelf) strongSelf = weakSelf;
return nil;
}];