上一篇已经讲解了MRC与ARC的基本知识,本篇我们讲解MRC-block与ARC-block的基本内容。

在MRC时代,Block会隐式地对进入其作用域内的对象(或者说被Block捕获的指针指向的对象)加retain,来确保Block使用到该对象时,能够正确的访问。

这件事情在下面代码展示的情况中要更加额外小心。

MyViewController *myController = [[MyViewController alloc] init…];

// 隐式地调用[myController retain];造成循环引用

myController.completionHandler =  ^(NSInteger result) {

[myController dismissViewControllerAnimated:YES completion:nil];

};

[self presentViewController:myController animated:YES completion:^{

[myController release]; // 注意,这里调用[myController release];是在MRC中的一个常规写法,并不能解决上面循环引用的问题

}];

在这段代码中,myController的completionHandler调用了myController的方法[dismissViewController...],这时completionHandler会对myController做retain操作。而我们知道,myController对completionHandler也至少有一个retain(一般准确讲是copy),这时就出现了在内存管理中最糟糕的情况:循环引用!简单点说就是:myController retain了completionHandler,而completionHandler也retain了myController。循环引用导致了myController和completionHandler最终都不能被释放。我们在delegate关系中,对delegate指针用weak就是为了避免这种问题。

不过好在,编译器会及时地给我们一个警告,提醒我们可能会发生这类型的问题:

对这种情况,我们一般用如下方法解决:给要进入Block的指针加一个__block修饰符。

这个__block在MRC时代有两个作用:

•说明变量可改

•说明指针指向的对象不做这个隐式的retain操作

一个变量如果不加__block,是不能在Block里面修改的,不过这里有一个例外:static的变量和全局变量不需要加__block就可以在Block中修改。

MyViewController * __block myController = [[MyViewController alloc] init…];

// ...

myController.completionHandler =  ^(NSInteger result) {

[myController dismissViewControllerAnimated:YES completion:nil];

};

//之后正常的release或者retain

在ARC引入后,没有了retain和release等操作,情况也发生了改变:在任何情况下,__block修饰符的作用只有上面的第一条:说明变量可改。即使加上了__block修饰符,一个被block捕获的强引用也依然是一个强引用。这样在ARC下,如果我们还按照MRC下的写法,completionHandler对myController有一个强引用,而myController对completionHandler有一个强引用,这依然是循环引用,没有解决问题:(

于是我们还需要对原代码做修改。简单的情况我们可以这样写:

__block MyViewController * myController = [[MyViewController alloc] init…];

// ...

myController.completionHandler =  ^(NSInteger result) {

[myController dismissViewControllerAnimated:YES completion:nil];

myController = nil;  // 注意这里,保证了block结束myController强引用的解除

};

在completionHandler之后将myController指针置nil,保证了completionHandler对myController强引用的解除,不过也同时解除了myController对myController对象的强引用。这种方法过于简单粗暴了,在大多数情况下,我们有更好的方法。

这个更好的方法就是使用weak。(或者为了考虑iOS4的兼容性用unsafe_unretained,具体用法和weak相同,考虑到现在iOS4设备可能已经绝迹了,这里就不讲这个方法了)(关于这个方法的本质我们后面会谈到)

为了保证completionHandler这个Block对myController没有强引用,我们可以定义一个临时的弱引用weakMyViewController来指向原myController的对象,并把这个弱引用传入到Block内,这样就保证了Block对myController持有的是一个弱引用,而不是一个强引用。如此,我们继续修改代码:

MyViewController *myController = [[MyViewController alloc] init…];

// ...

MyViewController * __weak weakMyViewController = myController;

myController.completionHandler =  ^(NSInteger result) {

[weakMyViewController dismissViewControllerAnimated:YES completion:nil];

};

这样循环引用的问题就解决了,但是却不幸地引入了一个新的问题:由于传入completionHandler的是一个弱引用,那么当myController指向的对象在completionHandler被调用前释放,那么completionHandler就不能正常的运作了。在一般的单线程环境中,这种问题出现的可能性不大,但是到了多线程环境,就很不好说了,所以我们需要继续完善这个方法。

为了保证在Block内能够访问到正确的myController,我们在block内新定义一个强引用strongMyController来指向weakMyController指向的对象,这样多了一个强引用,就能保证这个myController对象不会在completionHandler被调用前释放掉了。于是,我们对代码再次做出修改:

MyViewController *myController = [[MyViewController alloc] init…];

// ...

MyViewController * __weak weakMyController = myController;

myController.completionHandler =  ^(NSInteger result) {

MyViewController *strongMyController = weakMyController;

  if (strongMyController) {

// ...

[strongMyController dismissViewControllerAnimated:YES completion:nil];

// ...

}

else {

// Probably nothing...

}

};

到此,一个完善的解决方案就完成了:)

以上就是block在ARC与MRC的用处,希望对大家有所帮助!!!

MRC-block与ARC-block的更多相关文章

  1. 对于block的理解,block的面试题

    1.block跟swift中的闭包(closure)基本一样,都常用于值的回调,特别是在多线程的网络请求回调中,使用起来极为方便. 2.block的开头是"^",接着是由小括号所报 ...

  2. CSS 概念 Block Inline Containing block

    Block 元素 包括 "block-level box," "block container box," and "block box" ...

  3. OC:Block语法、Block使用、Block实现数组排序

    Block //定义一个求两个数最大值函数 int maxValue (int ,int); //函数的实现 int maxValue (int a, int b){ return  a > b ...

  4. Lucene4.2源码解析之fdt和fdx文件的读写(续)——fdx文件存储一个个的Block,每个Block管理着一批Chunk,通过docID读取到document需要完成Segment、Block、Chunk、document四级查询,引入了LZ4算法对fdt的chunk docs进行了实时压缩/解压

    2       索引读取阶段 当希望通过一个DocId得到Doc的全部内容,那么就需要对fdx/fdt文件进行读操作了.具体的代码在CompressingStoredFieldsReader类里面.与 ...

  5. Lucene4.2源码解析之fdt和fdx文件的读写——fdx文件存储一个个的Block,每个Block管理着一批Chunk,通过docID读取到document需要完成Segment、Block、Chunk、document四级查询,引入了LZ4算法对fdt的chunk docs进行了实时压缩/解压

    前言 通常在搜索打分完毕后,IndexSearcher会返回一个docID序列,但是仅仅有docID我们是无法看到存储在索引中的document,这时候就需要通过docID来得到完整Document信 ...

  6. Block 在 ARC 下的拷贝

    前言 现在有一种说法,是开启arc选项时,已经没有栈上的block了,所以所有的block都不需要copy来拷贝到堆上了.那么这个说法正确与否呢? 结论是这个说法必须是错误的,首先的一点就是arc只是 ...

  7. block 在ARC和非ARC下的不同含义

    Block的循环引用 对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中使用的对象: 对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中使用的对 ...

  8. 堆block和栈block的区分

    0. 问题所在 下面给出一段代码: - (NSArray*) getBlockArray { int num = 916; return [[NSArray alloc] initWithObject ...

  9. Objective-C中Block语法、Block使用以及通过Block实现数组排序

    Block:语法块,本质上是匿名函数(没有名称的函数) 标准C里面没有Block,C语言的后期扩展版本,加入了匿名函数 在C++.JS.Swift等语言有类似语法,叫做闭包 Block语法和C语言里的 ...

  10. iOS 中的block异常 判断block是否为空

    我们在调用block时,如果这个block为nil,则程序会崩溃,报类似于EXC_BAD_ACCESS(code=1, address=0xc)异常[32位下的结果,如果是64位,则address=0 ...

随机推荐

  1. 真正的ddos防御之道,简单干脆有效!

    话说,30G 就各种发博客 BB,唉,坦白说 ,博客园团队真心没见过世面 来 各位 先看图 啥意思呢? 就是哥的 最高防御是 600G.  没错,基本对当时的游戏没啥大的影响,10秒内恢复. 因为时间 ...

  2. [LeetCode] Push Dominoes 推多米诺骨牌

    There are N dominoes in a line, and we place each domino vertically upright. In the beginning, we si ...

  3. linux-Vim命令合集

    Vim命令合集 命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filena ...

  4. vue变异方法

    push()  往数组最后面添加一个元素,成功返回当前数组的长度    pop()  删除数组的最后一个元素,成功返回删除元素的值    shift()  删除数组的第一个元素,成功返回删除元素的值u ...

  5. 1 eclipse 离线安装activiti插件

    第一步:下载需要的离线activiti文件: 链接:https://pan.baidu.com/s/1-_XjIsuZfhiEZn6iLul6-Q  密码:mfyk  (这是其他网友的链接) 第二步: ...

  6. 几个比较常用的jar包

    implementation 'com.android.support:recyclerview-v7:26+'implementation 'org.greenrobot:eventbus:3.1. ...

  7. Javascript高级编程学习笔记(92)—— Canvas(9) 渐变

    渐变 渐变由 canvasGradient 实例表示 要创建一个渐变对象需要调用 createLinearGradient() 方法 该方法接收四个参数: 起点的x坐标 起点的y坐标 终点的x坐标 终 ...

  8. scala查询dataFrame结构

    println(dataFrame.printSchema)

  9. Python内置函数(11)——classmethod

    英文文档: classmethod(function) Return a class method for function. A class method receives the class as ...

  10. Java核心技术及面试指南 多线程并发部分的面试题总结以及答案

    7.2.10.1有T1.T2.T3三个线程,如何保证T2在T1执行完后执行,T3在T2执行完后执行? 用join语句,在t3开始前join t2,在t2开始前join t1. 不过,这会破坏多线程的并 ...