想必很多開發人員知道一般用copy修飾block,接下來就講解為什麼需要用copy,甚至會講到其實用strong修飾block也是可以的 在 Objective-C 語言中,一共有 3 種類型的 block: 新建一個項目,分別在ARC環境和MRC環境測試一遍 把測試文件改成MRC環境的方法: 把完 ...
想必很多開發人員知道一般用copy修飾block,接下來就講解為什麼需要用copy,甚至會講到其實用strong修飾block也是可以的
在 Objective-C 語言中,一共有 3 種類型的 block:
- _NSConcreteGlobalBlock 全局的靜態 block,不會訪問外部局部變數(顯然包括無外部變數或者全局變數)。
- _NSConcreteStackBlock 保存在棧中的 block,當函數返回時會被銷毀。
- _NSConcreteMallocBlock 保存在堆中的 block,當引用計數為 0 時會被銷毀。
新建一個項目,分別在ARC環境和MRC環境測試一遍
把測試文件改成MRC環境的方法:
把完整的測試代碼顯示如下:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,copy)void(^demoBolck)();
@property (nonatomic,strong)void(^demoBolck1)();
@end
@implementation ViewController
int b=8;//全局變數
- (void)viewDidLoad {
[super viewDidLoad];
void (^demoBolck)() = ^{
NSLog(@"indemoBolck");
};
NSLog(@"demoBolck %@",demoBolck); //<__NSGlobalBlock__: 0x1085af0e0> 無論ARC還是MRC下,因不訪問外部局部(包括無外部變數或者只有全局變數),NSGlobalBlock表示在全局區
void (^demoBolck4)() = ^{
NSLog(@"indemoBolck4 %d",b);
};
NSLog(@"demoBolck4 %@",demoBolck4); //<__NSGlobalBlock__: 0x10150b120> 全局區
__block int a = 6; //block內部引用a,並修改其值,需要用block修飾,不然可以不用
void (^demoBolck2)() = ^{
NSLog(@"indemoBolck2 %d",a++);
};
demoBolck2();
NSLog(@"demoBolck2 %@,%d",demoBolck2,a); //<__NSMallocBlock__: 0x600000056c50> ARC下堆區,在ARC模式下,系統也會預設對Block進行copy操作,Block的記憶體地址這時候便顯示在堆區 <__NSStackBlock__: 0x7fff5d0ada28>MRC下在棧區
NSLog(@"demoBolck2.Copy %@",[demoBolck2 copy]); //<__NSMallocBlock__: 0x600000056c50>copy操作不管MRC或者ARC都在堆區,只是在MRC下進行copy會改變地址
self.demoBolck = demoBolck2;
NSLog(@"self.demoBolck %@",self.demoBolck);//堆區<__NSMallocBlock__: 0x608000052630>
self.demoBolck1 = demoBolck2;
self.demoBolck1(); //demoBolck2 7 能執行無問題
NSLog(@"self.demoBolck1 %@",self.demoBolck1); //<__NSMallocBlock__: 0x600000056c50> strong修飾ARC和MRC都並沒有問題, 但是assign和retain在MRC環境下是還是在棧區的,會有問題
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//註意:MRC環境下:demoBolck1用assign,retain修飾,棧區:<__NSStackBlock__: 0x7fff50915a50>,提前釋放了所以運行到下麵語句程式會崩潰。ARC環境下:用copy,strong, assign, retain修飾是可以正常列印出結果的。 無論什麼環境,用copy,strong修飾是可以正常列印出結果的
self.demoBolck1();
}
@end
總結:
- block內部沒有調用外部局部變數時存放在全局區(ARC和MRC下均是)
- block使用了外部局部變數,這種情況也正是我們平時所常用的方式。MRC:Block的記憶體地址顯示在棧區,棧區的特點就是創建的對象隨時可能被銷毀,一旦被銷毀後續再次調用空對象就可能會造成程式崩潰,在對block進行copy後,block存放在堆區.所以在使用Block屬性時使用copy修飾。但是ARC中的Block都會在堆上的,系統會預設對Block進行copy操作
- 用copy,strong修飾block在ARC和MRC都是可以的,都是在堆區