全局块, 栈块及堆块

        最近比较空, 刚好有些时间可以看看书, 总结一下之前的知识, 本人空闲的时候, 有一种深深的焦虑, 感觉总该学点什么, 时代变化太快, 自己学的只是总结的也不是很充分, 一天天混了过去, 不如充实的过好美一天, 毕竟都是24小时, 由于最近很多直接写在了印象笔记中, 好多都没有写在博客上, /(ㄒoㄒ)/~~还是不扯了, 赶紧总结我的.

定义块的时候, 其所占的内存区域是分配在栈中的. 也就是说, 块只在定义它的那个范围内有效. 例如, 如下的代码可能就会很危险

void (^block)();

if(/* some condition */) {

   block = ^{

   NSLog(@"Block A");

   }

} else {

block = ^{

   NSLog(@"Block B");

   }

}

block();

      上面的两个块都分配在栈中. 编译器会给每个块分配栈内存,然而等离开了相应的范围之后, 编译器可能把分配给会的内存覆写掉.于是, 这两个块只能保证在对应的if或者else语句范围内有效. 这样写出来的代码可以编译, 但是运行起来时而正确,时而错误. 若编译器未覆写待执行的块, 则程序照常运行, 若覆写, 则程序崩溃.

    为解决此问题, 可给对象发送copy消息以拷贝之,这样的话, 就可以把块从栈复制到堆上了,拷贝后的块,可以在定义范围之外使用. 而且, 一旦复制到堆上, 块就成了带引用计数的对象了, 后续的复制操作都不会真的执行复制,只是递增块对对象的引用计数.如果不再使用这个块, 那就应该将其释放, 在ARC环境下会自动释放, 而手动管理引用计数时则需要自己来调用release方法,当引用计数降为0后, 分配在堆上的块, 会向其他对象一样, 为系统所回收. 而分配在栈上的块, 则无需明确会像其他对象一样, 为系统所回收. 刚才那段范例代码有危险, 原因就是这样的. 我们可以给代码加上两个copy方法调用, 就可以另其变得安全了;

除了堆块和栈快之外, 还有一类块叫做"全局块".这种块不捕捉任何状态(比如外围的变量等), 运行时也无需有状态来参与. 块所使用的整个内存区域, 在编译期已经完全确定, 因此, 全局块可以声明在全局内存里, 而不需要在每次用到的时候于栈中创建. 另外, 全局块的拷贝操作是个空操作, 因为全局块绝不可能为系统所回收, 这种块实际上相当於单利. 下面就是个全局块

void (^block)() = ^{

                        NSLog(@"This is a block");

                        };

由于运行该块所需的全部信息都能在编译期确定, 所以可把它做成全局块. 这完全是中优化技术; 若把如此简单的块当成复杂的块来处理, 那就会在复制以及丢弃该块时执行一些无谓的操作.





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章