要解释为什么ARC下我们修饰block属性时使用copy,首先我们应该搞清楚在MRC下是怎么回事。因为ARC是由MRC演变而来,搞清楚了MRC下的原理自然就明白ARC下是怎么回事了。
在MRC下block一共有是那种存储形式,全局区,栈区,堆区。
全局区block不访问外部变量,栈区block访问外部变量,堆区是执行[block copy]后会在堆区;
内存管理几个知识点:
iOS的内存管理一般分为两部分,堆区和栈区,
1.栈区的内存由系统自动管理,不需要程序员来操心。
2.堆区的难处需要程序员手动去管理,尽管后边苹果引入了ARC机制。但是ARC的机制其实仅仅是系统帮助程序员添加了retain,release,autorelease代码,并不是说系统就可以自动管理了。他的系统管理的原理还是MRC,并没有本质区别,仅仅是让程序员少写了大量的胶水代码而已。
关于函数返回的概念:
在一个函数的内部,return的时候返回的都是一个拷贝,不管是变量、对象还是指针都是返回拷贝,但是这个拷贝是浅拷贝。
1.对于直接返回一些基本类型的变量来说,直接返回值的拷贝就好,没有问题。
2.对于返回一些非动态分配(new/malloc)得到的指针就可能出现问题,因为尽管你返回了这个指针地址。但是这个指针可能指向的栈内存,栈内存在函数执行完毕后就自动销毁了。如果销毁之后你再去访问,就会访问坏内存会导致程序崩溃。
明确上边两个概念之后,就好说了。
在MRC下,如果一个block作为参数,没有经过copy就返回。后果是什么呢?因为在返回后这个block对应的栈内存就销毁了。如果你多次调用这个block就会发现,程序会崩溃。崩溃原因就是上边所说,block占用的空间已经释放了,你不可以进行访问了。
解决方案:就是在返回的时候,把block进行拷贝作为参数进行返回。这样做的好处是返回的那个block存储空间是在堆内,堆内的空间需要程序员自己去释放,系统不会自动回收,研究不会出现访问坏内存导致的崩溃了。
上边的解决方案,也就是我们在mrc下需要使用copy修饰符的原因。