1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| /** 通俗理解, MRC下不使用copy修饰, block存储在栈区, 作用域结束, block这个局部变量被销毁, 而一个 strong指针还指向了这个被回收的地址.所以使用copy,把block拷贝到堆区, 并且指向堆区的block. 但是在ARC下无论copy,还是stong都无所谓, 因为系统已经在创建block的时候, 已经拷贝到堆区了.
在 Objective-C 语言中,一共有 3 种类型的 block: __NSGlobalBlock__ 全局的静态 block,不会访问外部局部变量。 __NSStackBlock__ 保存在栈中的 block,访问外部局部变量,当函数返回时会被销毁。 __NSMallocBlock__ 保存在堆中的 block,当引用计数为 0 时会被销毁。
*/
@interface Test () @property (nonatomic, copy) void(^block)(); @end @implementation Test - (void)viewDidLoad { [super viewDidLoad]; //1 __NSGlobalBlock__ 全局block 存储在代码区(存储方法或者函数) void(^block1)() = ^() { NSLog(@"一探究竟block1"); }; NSLog(@"block1 %@",block1); //2 __NSStackBlock__ 栈block 存储在栈区 //block内部访问外部变量 int n = 5; void(^block2)() = ^() { NSLog(@"一探究竟block2 %d", n); }; NSLog(@"block2 %@", block2); //3 __NSMallocBlock__ 堆block 存储在堆区 对栈block做一次copy操作 void(^block3)() = ^() { NSLog(@"一探究竟 block3%d", n); }; NSLog(@"block3 %@", [block3 copy]); /* 由以上可以看出当block没有访问外界的变量时,是存储在代码区, 当block访问外界变量时时存储在栈区, 而此时的block出了作用域就会被释放 以下示例: */ [self test]; //当此代码结束时,test函数中的所有存储在栈区的变量都会被系统释放, 因此如果属性的block是用assign修饰时 当再次访问时就会出现野指针访问. self.block(); } - (void)test { int n = 5; [self setBlock:^{ NSLog(@"block %d",n); }]; NSLog(@"test--%@",self.block); }
|