Block的声明:
1,void (^myBlock)()
2,int (^myBlock)(float,int)
3,NSString* (^myBlock)(int, NSString*)
也可以使用Typedef为Block定义别名。
三种Block的特性
Block是一个Object对象,所以我们需要对它进行内存管理。
Block分为三种,NSConcreteStackBlock,NSConcreteMallocBlock,NSConcreteGlobalBlock。
表面上看都是Block,但是它的isa指针会指向这三种不同的Block,后面会介绍isa。
下面分别解释这三种Block:
NSConcreteStackBlock,栈Block。
当Block中只用到外部局部变量,成员变量,并且没有强指针引用的Block都是StackBlock。
这种Block由系统管理内存,并且不会持有对象,对它进行retain,release也会无效,copy后会变成MallocBlock。
NSConcreteMallocBlock,堆Block。
用copy修饰的block会copy一份到堆上,成为MallocBlock,ARC中用strong修饰也会执行copy。
这种Block需要手动管理内存,并且会持有对象。
NSConcreteGlobalBlock,全局Block。
没有用到外部变量或者只用到全局变量或静态变量的Block是GlobalBlock。
这种Block生命周期是应用开始到结束。
不会持有对象,对它进行retain,release,copy都会无效。
我们在使用block的时候,并不希望让系统去管理内存,这样很不安全。
所以要把StackBlock通过copy变成MallocBlock再去使用。
当Block作为属性的时候,我们可以加入copy的关键字。
当Block作为方法参数传入的时候,我们可以手动去copy。
循环引用
从上面我们看到MallocBlock会持有对象。
当在Block中使用self的时候,由于self持有者该block,block又持有self,就会造成循环引用。
这时有如下几种办法:
1,通过加入weak弱引用self去解决,__weak __typeof(self)weakSelf = self;
其中__typeof(self)的意思是创建一个与self相同类的实例。
如果在Block中多次使用self,我们需要强引用去防止被提前释放,__strong __typeof(self)strongSelf = weakSelf;
2,使用类方法传入block,让别的类去持有,这样别的类持有block,block持有self,当别的类被释放的时候,block就会被释放,self也会被释放。
这样做self相当于被别的类持有。
3,在block执行完成以后,手动去将block设为 nil,从而释放block持有的self。
block持有self的时候,当block释放以后,self也就会被释放了。
__block
Block中不可以修改或赋值,需要添加__block修饰。
但是NSMutableArray和NSMutableString的添加删除不需要添加__block修饰,因为地址并没有变。
isa
isa是元指针,每一个对象都有一个isa指针,指向类对象。
类对象也是对象,类对象的isa指针指向元类(meteClass)对象。
元类也是对象。所以元类也有isa指针,最终指向根元类(root meteClass)对象,根元类则指向自身。
元类中保存了类方法列表,类版本号,类名等信息。
类方法其实就是调用元类的方法列表,当类方法被调用的时候会先从本身查找类方法的实现,如果没有,会向父类查找。