美文网首页
关于block的认识

关于block的认识

作者: Carson_Zhu | 来源:发表于2018-02-02 16:11 被阅读3次

前言

block是一种比较特殊的数据类型。它可以保存一段代码,在合适的时候取出来调用。

block的声明
  • 方式一
typedef int(^myBlock)(int, int);

@interface Person : NSObject
@property (nonatomic, copy) myBlock myBlock;
@end
  • 方式二
@property (nonatomic, copy) void (^callback)(NSString *name);
  • 方式三
- (void)func:(int (^)(int, int))callback;
block的实现
self.carson.callback = ^NSString *(NSString *name) {
    NSLog(@"%@", name);
};
block的作用域

block需要注意的一个特性就是Variable Capturing,直译过来就是捕捉变量。block会将“捕捉”到的变量复制一份,然后对复制品进行操作。如果希望block作用域内可以修改外边的变量,可以使用__block

__block int i = 0;
self.carson.callback = ^NSString *(NSString *name) {
    NSLog(@"%@", name);
    i ++;
};
somePerson.callback(@"张三");
NSLog(@"i == %d", i);

打印结果:

2018-02-02 15:53:13.386997+0800 Block[6754:448733] i == 1
block的三种类型
  • _NSConcreteGlobalBlock(全局block)
    全局块存储在静态区(也叫全局区),相当于Objective-C中的单例。

  • _NSConcreteStackBlock (栈块)
    栈块存储在栈区,超出作用域则马上被销毁。

  • _NSConcreteMallocBlock(堆块)
    堆块存储在堆区中,是一个带引用计数的对象,需要自行管理其内存。

怎么判断一个block所在的存储位置呢?

  • block不访问外界变量(包括栈中和堆中的变量)此时就为全局块
  • 访问外界变量的block默认存放在堆中,实际上是先放在栈区,在ARC情况下自动又拷贝到堆区,自动释放。如果不是ARC则存放在栈区,。
  • 使用copy修饰符的作用就是将block从栈区拷贝到堆区
声明block属性的时候为什么用copy

使用copy修饰符的作用就是将block从栈区拷贝到堆区,复制到堆区的主要目的就是保存block的状态,延长其生命周期。因为block如果在栈上的话,其所属的变量作用域结束,该block就被释放掉。

不同类型的block使用copy方法的效果也不一样,如下所示:

block的循环引用

在使用block的时候,我们要特别注意循环引用的问题,先来看一个循环引用的例子:

@interface Person : NSObject
@property (nonatomic, copy) void (^callback)(NSString *name);
@property (nonatomic, assign) NSInteger age;
@end
@interface ViewController ()
@property (nonatomic, strong) Person *carson;
@end
self.carson.callback = ^void (NSString *name) {
    self.carson.age = 5;
};

在上面的代码中Person类声明了一个block属性,所以Person对象carsonblock有一个强引用。而在block内部又对carson进行了一次强引用,这样就形成了一个封闭的环,也就是我们经常说的强引用循环。由于其相互引用,内存不能够进行释放,就造成了内存泄漏的问题。

__weak解决循环引用
__weak typeof(self) weakSelf = self;
self.carson.callback = ^void (NSString *name) {
    weakSelf.carson.age = 5;
};

但是在并发执行的时候,block的执行是可以抢占的,而且对weakSelf指针的调用时序不同可以导致不同的结果,比如在一个特定的时序下weakSelf可能会变成nil,这个时候在执行doAnotherThing就会造成程序的崩溃。为了避免出现这样的问题,采用__strong的方式来进行避免,更改后的代码如下:

__weak typeof(self) weakSelf = self;
self.carson.callback = ^void *(NSString *name) {
    __strong typeof(weakSelf) strongSelf = weakSelf;
    strongSelf.carson.age = 5;
};

总结:

  • self没有直接或间接强引用block,可以在block里面直接使用self,比如UIViewanimation动画block
  • self强引用对象方法里的block也可以直接使用self,因为没有强引用到block,所以不会造成循环引用。
  • 当和并发执行相关的时候,当涉及异步的服务的时候,block可以在之后被执行,并且不会发生关于self是否存在的问题。

相关文章

  • 关于block的认识

    前言 block是一种比较特殊的数据类型。它可以保存一段代码,在合适的时候取出来调用。 block的声明 方式一 ...

  • 关于block的浅层认识

    1.block要用copy修饰,还是用strong block本身是像对象一样可以retain,和release。...

  • Block的认识

    block的原理是怎样的?本质是什么?block是将函数及其执行上下文封装起来的对象或者说是结构体(3个关键字;继...

  • iOS面试之Block大全

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • iOS面试之Block模块

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • 详细的探讨一下Block(讨论篇、基础篇、实质篇)

    章节目录 关于Block的讨论篇 Block的基础篇 Block的实质篇 讨论篇: 为什么要看Block? 为了更...

  • oc Block

    标签:ios开发入门 对Block的经典认识 Block一点也不神秘

  • 关于block(4)

    关于block(4) 标签: iOS 技术 接上篇,我们继续探究block。 block的copy属性 研究到这里...

  • iOS对象间的通讯

    一、 Block 认识 Block Block 的循环引用 二、委托与数据源 委托与数据源 三、通知 一、Bloc...

  • block

    一.关于block block是将函数及其执行上下文封装起来的对象。 __block_impl结构体为 block...

网友评论

      本文标题:关于block的认识

      本文链接:https://www.haomeiwen.com/subject/aklezxtx.html