iOS 中Block的正确使用避免循环引用和Crash

Block的使用相对于一个函数,下面我们主要讲解下block在使用中遇到的循环引用,如何解决的问题进行讲解:
继MRC后苹果推出了ARC,方便了广大开发者解决内存管理问题,下面我们主要针对MRC时候block内存管理,有些细节不适用于ARC,例如MRC下_block不会增加引用计数,但是在ARC上会增加(下边有详细讲解),ARC下必须使用_weak修饰。

Block简介

Block的使用很像函数指针,不过与函数最大的不同是:Block可以访问函数以外、词法作用域以内的外部变量的值。换句话说,Block不仅 实现函数的功能,还能携带函数的执行环境。
可以这样理解,Block其实就包含两部分:
1:Block执行的代码,这是在编译的时候已经生成好的;
2:一个包含Block执行时需要的所有外部变量值的数据结构。 Block将使用到的、作用域附近到的变量的值建立一份快照拷贝到栈上
note:Block与函数另一个不同是,Block类似ObjC的对象,可以使用自动释放池管理内存(但Block并不完全等同于ObjC对象,后面将详细说明)。

Block与函数另一个不同是,Block类似ObjC的对象,可以使用自动释放池管理内存(但Block并不完全等同于ObjC对象,后面将详细说明)。

  • NSGlobalBlock:类似函数,位于text段;retain,release 无效
  • NSStackkBlock:位于栈区,函数返回后Block无效,retain,release无效,只有copy的时候才retainCount加1
  • NSMallocBlock:位于堆内存,retaiin,release,copy 加1
sumBlock blk1 = ^ long (int a, int b) {
  return a + b;
};
NSLog(@"blk1 = %@", blk1);// blk1 = <__NSGlobalBlock__: 0x47d0>


int base = 100;
sumBlock blk2 = ^ long (int a, int b) {
  return base + a + b;
};
NSLog(@"blk2 = %@", blk2); // blk2 = <__NSStackBlock__: 0xbfffddf8>

BlkSum blk3 = [[blk2 copy] autorelease];
NSLog(@"blk3 = %@", blk3); // blk3 = <__NSMallocBlock__: 0x902fda0>

为什么blk1类型是NSGlobalBlock,而blk2类型是NSStackBlock?blk1和blk2的区别在于,blk1没有使用Block以外的任何外部变量,Block不需要建立局部变量值的快照,这使blk1与函数没有任何区别,从blk1所在内存地址0x47d0猜测编译器把blk1放到了text代码段。blk2与blk1唯一不同是的使用了局部变量base,在定义(注意是定义,不是运行)blk2时,局部变量base当前值被copy到栈上,作为常量供Block使用。执行下面代码,结果是203,而不是204。

原文地址

你可能感兴趣的:(iOS,开发)