block简介
block跟swift中的闭包(closure)比较:
基本一样,都常用于值的回调,特别是在多线程的网络请求回调中,使用起来极为方便。
- Block格式:
block的开头是“^”,接着是由小括号所包起来的参数列,行为主体由大括号包起来。block有四种类型,分别是无参无返回、无参有返回、有参有返回、以及有参无返回,而一般使用的block都是有参block,因为使用block主要就是进行参数的传递。 - Block的循环引用问题:
使用block时要特别注意类的循环引用:例如在一个控制器中,self强指针指向一个对象,而这个对象又强指针指向一个block,而在block中,又强指针指向了self,从而造成循环引用,导致内存无法释放,造成内存泄露。
如何解决block的循环引用:
解决循环引用的方法,常用__weak来打断强引用,例如用__weak来定义一个weakself来指向self的地址,如果self被释放,weakself指向的地址变为nil,从而打断引用环。需要注意的是,__weak是ARC专有的,__unsafe__unretained可以用在ARC,也可以用于MRC,但__unsafe__unretained是“assign”形式,如果指向的对象被释放,其指针地址保持不变,如果继续使用该指针,就会出现“野指针”。 - 关于block内存管理:
当block内部没有引用外部变量时,block存放在全局区;在运行时发现, block的本质是静态的static修饰的,所有全局可用, 这也是block可以跨类跨控制器调用的原因, 在MRC下,当block内部引用外部变量时,block存放在栈区;当对该栈区的block进行copy操作时,block将存放在堆区。在ARC下,当block内部引用外部变量时,block存放在堆区;关于堆区与栈区的区别,栈区主要存放局部变量,定义的参数等,在函数结束,系统会自动回收其内存空间,而堆区一般用程序员自行分配释放,若程序员不释放,程序结束时,由系统回收。总的来说,使用栈区更为快捷,而使用堆区更为灵活。 - Block的使用注意点:
如果要在block中修改外部变量,当变量是static全局变量时,block可以直接修改,如果不是,可以用__block关键字来修饰,就可以在block内修改变量的值。
block代码示例
- 无参数无返回值的block
void(^helloBlock)() = ^ { NSLog(@"hello") } - 无参数有返回值的blokc
int(^intBlock)() = ^ { return 5 } - 有参数 无返回值的block
void(^giveInt)(int) = ^(int a){ NSLog(@"%d",a) } - 有参数有返回值block
int(^giveInt)(int) = ^(int a){ NSLog(@"%d",a) return a+1 }