浅谈iOS中的Block、oc中为什么会用copy修饰block、block和deleagte的区别

block 的修饰符为什么选copy

想必很多开发人员知道一般用copy修饰block,接下来讲解为什么需要用copy,甚至会讲到其实用strong修身符也是可以的.
在Objective-C 语言中,一共有3中类型的block:

  1. _NSConcreteGlobalBlock 全局静态block,不会访问外部局部变量
  2. _NSConcreteStackBlock 保存在栈区中的block,但函数返回时会被销毁.
  3. _NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁.

总结:

  • block内部没有调用外部局部变量时存放在全局区(ARC和MRC下均是)
  • block使用了外部局部变量,这种情况下也是我们平时常用的方式.MRC:Block的内部地址显示在栈区,栈区的特点就是创建的对象随时可能被销毁,一旦被销毁后续在次调用空对象就可能会造成程序崩溃,在对block进行copy后,block存放在堆区.所以在使用block属性时使用copy修饰.但ARC中block都会在堆上的,系统默认会对block进行copy操作.
  • 使用copy,strong修身block在ARC和MRC都可以的,都是在堆区

补充:

一个block要使用self.会在block外部申明一个weak变量指向self,然而为何有时会block里又申明一个strong变量指向weakSelf?

原因:

block会把写在block里面的变量copy一份,如果直接在block里面使用self,(self对变量默认是强引用)self对block持有,block对self持有,导致循环引用.所以这里需要声明一个弱引用weakSelf,让block引用weakSelf,打破循环引用.
而这样会导致另外一个问题,因为weakSelf对self是弱引用,如果这个时候控制器pop或者其他方式使引用计数为0,就会释放,如果block是异步调用,而且调用的时候self已经释放了,这个时候weakSelf已经变成nil了.当控制器(也可以是其他控制器)pop回来之后(或者一些其他原因导致释放),网络请求完成,如果这个时候需要控制器作出反应,需要strongSelf再对weakSelf强引用一下.但是,你可能会疑问,strongSelf对weakSelf强引用,weakSelf对self弱引用,最终也是对self进行了强引用,会导致循环引用吗?不会的,因为strongSelf是在block里声明的指针,当block执行结束后,strongSelf会释放,这个时候不将不再强引用weakSelf,所以self会正确的释放.

Bolck 和 Deleagte 的区别

block 和delegate 本质上都是回调,

在编码风格上

  • block更轻型,使用简单,能够直接访问上下问.使用block代码使代码更加紧凑,降低了代码的分散程度.使用deleagte,首先要去申明protocol协议,并且写上回调方法.然后在要实现的协议类中去实现.编码风格计较零散.

源头上的区别:

  • delegate运行成本低,block的运行成本高.block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是引用计数+1,使用完成或者block置nil后才能销毁.deleagte只保存了一个对象指针(要用weak修饰deleagte,不然也会造成循环引用),直接回调,没有其他额外的消耗.

使用场景上的区别

  • 多个相关方法.假如每个方法都设置一个block,这样会更麻烦.而deleagte让多个方法分成一组,只需要设置一次,就可以多次回调了.当多于3个方法时就应该优先采用delegate.当1,2个回调时则使用block
  • deleagte更安全些,比如:避免循环引用.使用block时稍微不注意就形成循环引用,导致对象释放不了.这种循环引用,一旦出现就比较难检查出来.而deleagte的方法时分开的.并不会引用上下文,因此更安全些.
0%