一、Block的简单介绍
Block 就是匿名函数 它是封装了一个代码块,这个代码块在什么时候都可以执行;
使用Block的步骤就三步:1.定义Block变量;2创建Block的代码块 3.调用Block
(1)无参无返回值
void (^one) = ^{ NSLog(@"hello world!"); }; 调用 one();
(2) 无参有返回值
int (^tow) = ^{ return 1; }; 调用 int a = tow();
(3) 有参无返回值
void (^three)(int) = ^(int a){ NSLog(@"hello world!"); }; 调用 int b = 2; three(b);
(4) 有参有返回值
int (^four)(int,int) = ^(int a,int b){ return a + b;); }; 调用 int a = 1; int b = 2;
int sum = four (a , b);
定义Block的另一种方式 一般用 typedef void (^BlockName)( );
二、Block的注意事项
typedef void (^BlockName)( );
1.调用Block的时候首先要判空if (self.BlockName){ 在这里调用Block:self.BlockName( ) };
2.Block可以访问局部变量,但是不能修改它的值;如果要修改的话该变量必须用__block修饰;
int a = 10; void(^BlockName)() = ^{ a++; }; 此处a的值不能修改
原因:此处不能修改的原因是在编译期间确定的,编译器编译的时候把a的值复制到block作为一个新变量(假设是a‘ = 10),此时a'和a是没有关系的
3.如果block块里边有self这样的代码, self必须用__weak 修饰;
__self ViewController *controller = self;
void(^BlockName)() = ^{ NSLog(@"%@", controller.string); };
原因:block会对内部的对象进行一次retain,也就是说self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。(一句话防止循环引用)
4.在申明block属性的时候用copy 后者strong修饰;
因为默认情况下,block是存档在栈中,可能被随时回收,需要copy到堆区一份,防止被释放掉;
@property(copy,nonatomic)BlockName myBlock;
5、在多线程环境下(block中的weakSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析构。
__weak __typeof(self)weakSelf =self;
AFNetworkReachabilityStatusBlock callback= ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf=weakSelf;
strongSelf.networkReachabilityStatus=status;if(strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
第四、五、六行,如果不转成strongSelf而使用weakSelf,后面几句话中,有可能在第四句执行之后self的对象可能被析构掉,然后后面的StausBlock没有执行,导致逻辑错误。
这里边的typeof(self) 指的是任意类型 ,还有一点 析构这个词的解释
需要注意的情况暂时能想到这么多!如还有其他请留言告诉我不甚感激!
三、Block的使用
Block的使用我就简单说几点应用场景,第一点 他可以传递参数,具体来说就是实现两个ViewController之间值的传递;
第二点 他可以代替代理来使用;
第三点 他可以作为变量来传值,一般在网络请求的时候用的比较多;
四、Block的底层实现 因为它涉及到了数据结构方面的知识