block备忘录

作者: Oneruofeng | 来源:发表于2016-11-17 23:37 被阅读82次

前言

随著blockiOS4.0OS X 10.6的引入,给事件传递一种新的方式实现,在开发中用得最多的场景莫过于事件回调。使用block相对与delegate的优势在于,业务集中,可读性强,代码内联,不像代理需要实现很多函数,在适当的场景选择这种方式实现事件传递或者传参效果非常好,现在很多开源项目都实现了两种方法的事件回调。

block用起来虽然很爽,但也有它的不足,存在循环引用,轻者内存泄露,甚至导致App崩溃,不易调试追溯,因此使用它使一定要小心。鉴于实践中的踩过各种坑,总结下来,方便自己和他人以后查阅,这就是block备忘录写作的初衷。

block的本质

block实际上是指向结构体的指针,编译时,block的内部代码生产对应的函数。

具体结构如下:

block结构图

与C语言的函数指针的区别

  • block的代码是内联的,效率高于函数调用
  • block对于外部变量默认是只读属性
  • blockObjective-C看成是对象处理

block声明

  • 作为property

    @property (nonatomic, copy) returnType (^blockName)(parameterTypes);

  • 作为方法参数

    - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

  • 作为一个方法调用参数

    [someObject someMethodThatTakesABlock:^returnType (parameters) {...}];

  • 作为一个typedef

    typedef returnType (^TypeName)(parameterTypes);

    TypeName blockName = ^returnType(parameters) {...};

  • 作为函数参数

    int (^sumOfNumbers)(int a, int b) = ^(int a, int b) {
    return a + b;
    };

SDWebImage中使用的block示例:

typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);

typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);

typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);

block调用

跟C函数类似使用(),括号里面还可以带一个或者多个参数

// block声明
(void)(^loggerBlock)(void); 

// block定义
loggerBlock = ^{ 
     NSLog("hello world")
};

// block调用
loggerBlock(); 

block内存管理

默认情况下,block是在栈内存中,它不会对所引用的对象进行任何操作;如果对block进行一次copy操作,block就会在堆内存中,并且它会它所有的引用的对象做一次retain操作

  1. 对于block外的变量引用,block 默认是将其复制到其数据结构中来实现访问的
  2. 对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的
  3. 而block会捕获代码外的局部变量,并且仅限于只读操作
  4. 在block中希望修改的外界局部对象,必须加上__block关键词

ARC

如果对象使用`__unsafe_unretained`或`__weak`修饰,就不会对其做`retain`操作

MRC

如果对象使用了`__block`修饰, 就不会对其做`retain`操作

为了防止block中的循环引用,可以用__weak关键词把相应的对象声明为弱引用,在block快内部需要多次访问,防止该对象被释放,可以用__strong关键词将声明为强引用:

__weak __typeof__(self) weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    __strong __typeof(self) strongSelf = weakSelf;
    
    [strongSelf doSomething];
    [strongSelf doOtherThing];
});

原文发表于王若风的技术博客

参考链接

相关文章

  • block备忘录

    前言 随著block在iOS4.0和OS X 10.6的引入,给事件传递一种新的方式实现,在开发中用得最多的场景莫...

  • block 备忘录

    引子 半夜突然想写点什么,又不想填之前的坑……因为懒,然后就想到了这个,感觉这应该算是block相关技巧,就根据缺...

  • iOS开发之Block原理探究

    Block概述 Block本质 Block调用 Block分类 Block循环引用 Block原理探究 Block...

  • block的使用

    定义block 返回类型 (^block名称)(参数) = ^(){block内容}; 调用block block...

  • Block 02 - __block

    Block 02 - __block __block 的作用 __block 可以解决 Block 内部无法修改 ...

  • iOS面试之Block大全

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

  • iOS面试之Block模块

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

  • iOS Block

    Block的分类 Block有三种类型:全局Block,堆区Block,栈区Block 全局Block 当Bloc...

  • iOS block 为什么官方文档建议用 copy 修饰

    一、block 的三种类型block 三种类型:全局 block,堆 block、栈 block。全局 block...

  • iOS开发block是用copy修饰还是strong

    Block分为全局Block、堆Block和栈Block1、在定义block没有引用外部变量的时候,block为全...

网友评论

    本文标题:block备忘录

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