Block在类中的使用:
1.block在类中作为参数
返回类型
-(void)gotoSchool:(void (^)(NSString *name))myBlock;
参数 block名称
指向一个函数栈空间
2.在类中声明为属性 形参
@property(copy) void (^myBlock)(NSString *name);
^为block标志 myBlock为block的名称
Block 属性的声明,首先需要使用copy修饰,只有copy后的block才会放在堆中,栈中的Block生命周期是和栈绑定的,栈中变量的生命周期是由系统决定的。
另一个需要注意的问题是关于线程安全,在声明Block属性时,需要确认“再调用Block时另一个线程有没有可能去修改Block?”。如果确定不会有这种情况的发生,那么Block属性就可以使用nonatomic来修饰,如果不确定的话(一般都是这种情况),那么你首先需要声明Block属性为atomic,也就是保证变量的原子性
atomic :在多线程环境下,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题
nonatomic:如果该对象无需考虑多线程的话,我们可以使用这个属性,这样是编译器少生成一些互斥加锁代码,这样可以提高效率
atomic 是objc使用的一种多线程保护技术,主要是防止在写入数据未完成时,被其他线程读取数据,造成数据错误,这种机制是非常浪费系统资源的,一般在手机设备上,如果没有用多线程间的通讯编程,我们可以使用nonatomic来提高系统效率。
例如,我们先定义一个Block
typedef void (^MyBlockType)(NSString name);
接着使用Block声明一个属性,系统默认是atomic属性
@property(copy) MyBlockType myBlock;
虽然有了atomic来保证属性的原子性,但是还没有达到线程安全,再调用时,我们先把block赋值给本地变量,防止Block突然改变,如果不这样做的话,即使我们判断了Block属性不为空,在调用之前,如果另一个线程突然把block属性设置为空,那么就会造成程序的crash
代码如下:
// 不完善代码,可能会造成crash
if(self.myBlock)
{
//在这里 self.myBlock可能被另一个线程设置为空,这样就会造成crash,atomic只会确保myBlock的原子性,这种操作本身还是非线程安全的。
self.myBlock("哈哈");
}
// 正确的代码
MyBlock block=self.myBlock;
if(block){
block("哈哈")
}
(MRC)
MyBlock block=[self.myBlock retain];
if(block){
block("哈哈")
}
[block release];
在这里如果不使用retain的话,block就不具备持有self.myBlock对象,如果self.myBlock被设置为空,就有可能使block变成野指针。
关于循环引用问题
在ARC下,在调用Block时,我们要使用__weak来修饰self,只有这样我们才可以解决循环引用的问题。
使用 __weak修饰的指针,在使用后系统自动给它赋值为nil
//iOS 5之前可以用__unsafe_unretained
//__unsafe_unretained typeof(self) weakSelf = self;
__weak typeof (self) weakSelf=self;
self.myblock_1:^(NSString *) {
[weakSelf run];
};
在非ARC 显然我们不能使用弱引用,这里我们直接使用block 来修饰,记住在这里使用block不会造成循环引用。
__block typeof (self) weakSelf=self;
self.myBlock:^(NSString *){
[weakSelf run];
}