(1)Block是C语言的,是一种数据类型。Block出现后,很多代理都会被替代。Block是一种数据类型,是提前准备好的代码段,在需要的时候执行。其实就像调用一个函数一样。准备代码就是{},执行就是();
(2)Block常见问题:
*在定义Block时,如果引用了外部变量,会对外部变量做一次copy,记录住定义block时候变量的值,如果后续这个变量变了,也不会影响block的变化,这一瞬间是几就是几
*默认情况下不允许Block修改外部变量,因为拷贝是const拷贝。因为Block可以当一个函数,不应该破坏外部细节(就像NSString用copy一样不可变)
*如果要修改外部变量,用__block 修饰。不过修饰后,这个变量的地址永久变成了堆区了(不加__block修饰的,是一个栈一个堆,是两个地址,所以没法改)。
*如果访问的外部变量是一个OC对象(NSString Person*),那么其实只是拷贝到堆区的只是 这个OC对象在栈区的指针(*p),指针指向的内容还是在堆区的内容,没有变,唯一变的只是指针的地址,而不是指针指向的地址。此时,修改NSString的内容,其实没事!因为Block拷贝的是指向这个内容的地址。
(3)Block的应用场景:
*当做参数:用的很多。
*当做返回值:需要先定义这个返回值类型的Block(TypedefBlock),这一步类似定义了int,然后再声明。当做返回值用的比较少,用于框架比较多。
*控制器/自定义视图传值回调 , 异步任务回调。
(4)多个控制器反向传值:
*代理:我传递数据的话,我写@propertyDelegate,我写协议,你遵守我,我给你值。
*Block:我传递数据的话,我写@propertyBlock,我写Block,我来调用Block(),你来填充Block的内容(就是代理的实现,只是写在了一起)。
如果回调方法比较少,一个方法里,有三个以内的block就差不多可以了,如果很多还是用代理吧。Block的好处就是所有代码都在一起,便于维护,好多在一起反而不好了。例如UITableView的代理方法有小20个,数据源方法也有10多个,像这种分工明确,回调多,但是不需要每一个方法都必须事件,这时候就用代理。
Block和代理都需要判断是否执行。Block如果不判断,对方没有实现Block内容的话,就会野指针EXC_BAD_ACCESS,因为找方法找不到。
(5)Block的循环引用:__weak *weakSelf = self;
/**
block的陷阱-有可能会出现循环引用
解决办法:
1. 要对内存对象之间的引用关系要清楚
技巧:
1. 在block中碰到self,要格外小心,有可能会出现循环引用,通常最好思考一下
2. 利用dealloc协助判断!如果不能被正常释放就说明有循环引用!
*/
(6)UINavigationControllers有个ViewControllers属性,这个其实是栈处理器。说白了就是子控制器之间都是NaviController管理的,A,B,C子控制器被弹出来的时候,是ViewCotrollers数组对A,B,C进行强引用。而不是B弹出C,B强引用C。所以这一波控制器之间的传递Block其实是没有循环引用的,但是自定义View和控制器之间就很可能循环引用。所以看到self.就思考下是否循环引用。