Block(Closure) Tips

使用 Block 的时候谨记以下几点:

1.Block类型:全局块(Global Block)和堆块(Heap Block),以及栈块(Stack Block)。
2.变量捕获: 默认无法修改变量,需要添加 __block 修饰符
3.避免循环引用。

推荐文章:
1.官方文档:
快速上手:Working with Blocks,进阶:Blocks Programming Topics
2.优秀博客:
Deep into Block: A look inside blocks: Episode 1, Episode 2, Episode 3
底层实现:谈 Objective-C Block 的实现 - By 唐巧
类型探讨:Objective-C Blocks Quiz
啥都有:对 Objective-C 中 Block 的追探

类型

之前看文档或是其他人写的文章都讲述了三种 Block 类型,但直到看到上面的测试,我才意识 Block 类型是如何决定的。经过一些实践,简单来说,在 Objective-C 中:
1.Block 中没有使用外围变量的话,在开启 ARC 的条件下,因为不需要依赖其他状态,其使用的内存区域在编译期就可以确定,将会被编译为全局块;而没有开启 ARC 时,总是被编译为栈块。
在唐巧的博客中使用 Clang 来研究 Block ,这里也学习了一下,但是基本上这些块都是被编译为栈块,按照唐巧的说法,在 ARC 下,是被编译为全局块的。

《Effective Objective-C 2.0》给出如下的例子:声明了一个 Block,但需要根据条件来选择合适的实现。

void (^block)();
if(条件 A) {block = ^{NSlog(@"Block A");}
}else{ block = ^{ NSLog(@"Block B"); } } block()

上面这段代码的问题在于,这两个块只在相应的 if 或 else 语句范围内有效,离开了相应的范围后,编译器有可能覆写块所在的内存。这样的代码可以编译,但在运行时可能出错。书中提出,这里可以使用 copy 操作将块拷贝到堆上,这样一来,块可以在定义它的范围外使用。正确写法如下:

void (^block)();
if(条件 A) {block = [^{NSlog(@"Block A");} copy]; }else{ block = [^{ NSLog(@"Block B"); } copy]; } block()

书中没有提及此处是否开启了 ARC;我将上述代码编写在 C 文件中,使用 Clang 将之转化为 cpp 实现后,发现这里是个栈块;而按照上一条的说法,开启 ARC 后,这里将会被编译为全局块。那么在开启 ARC 的条件下,这段代码是否有问题呢?答案是没有,因为原来的代码的问题在于块的内存在栈中,而开启 ARC 下,块编译为全局块,不存在这个问题。
在 Objective-C Blocks Quiz 的 Example C中,提到:

That’s correct. Since the block doesn’t capture any variables in its closure, it doesn’t need any state set up at runtime. it gets compiled as an NSGlobalBlock. It’s neither on the stack nor the heap, but part of the code segment, like any C function. This works both with and without ARC.

2.使用了外围变量的话,若开启了 ARC,则只会被编译为堆块,内存是分配在堆上的;若没有开启 ARC,函数中定义的 Block 将会编译为栈块(如今除了旧项目很少有不开启 ARC 的吧)。

总结下:开启 ARC 的条件下,将不会有栈块,这样可以省去不少麻烦,但是 Objective-C Blocks Quiz 的最后也提到LLVM的一位维护者说:

We consider this to be a compiler bug, and it has been fixed for months in the open-source clang repository. What that means for any hypothetical future Xcode release, I cannot say. :)

保险点,开启 ARC。

生命周期

栈块,顾名思义,离开了定义它的函数范围就被收回了;堆块,就像普通的对象一样采用引用计数机制;全局块,在应用的整个生命周期都存在。

变量捕获 + 循环引用

在声明块的范围内,所有变量都可以被块捕获(就是可以使用)。默认情况下,不可以在块里修改外围的变量,因为块拷贝了一份变量到它的内存中,对于对象则是拷贝了对象的地址;若想修改,需要在外围变量前面添加修饰符 __block。是否添加 __block 修饰符,源代码会有很大不同,可以在唐巧的博客里看到。另外,Block 最著名的问题就是循环引用,就是由于互相保持着对方的引用,所以 ARC 拿这俩没办法,将会一直存在;复杂一点的,多个对象对其他对象的引用形成了一个圈,ARC 也是没办法。一般的解决办法是,在形成的引用圈的一处使用弱引用,这样就有机会打破强引用圈。

常见的循环引用陷阱是在类中定义了块变量,然后在块中使用了类实例的属性。而在访问属性的同时,块实质上隐式地捕获了当前实例,这样一来就造成了循环引用。
在 Objective-C 中,解决方法通常如下:

__weak myClass *weakSelf = self;
self.block = ^{__strong myClass *strongSelf = weakSelf;//防止当前 self 为空 if(strongSelf){ [strongSelf doSomeThing]; } }

又或者使用 typeof,不过这种高级技巧,可读性就不敢保证了。今天这条微博引起了一些讨论:


是否会捕获 self


这个代码的关键在于 typeof(self),因为它在块的内部出现,那么块是否捕获了 self呢?答案是不会,因为 typeof是个编译符号,在编译期间起作用,而不是运行时,因此这么写不会造成循环引用的问题。

在 Swift 中,针对这个问题有了更加优雅的解决方案:捕获列表(Capture List)。在闭包参数前添加列表,从属关系以及捕获对象成对为一组值,多组值用「,」隔开。
无参数:

var someClosure: () -> Void = {[unowned self, weak delegate = self.delegate!] in //closure body }

有参数:

var someClosure: (Int, String) -> String = {[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) in //closure body }

 

转载于:https://www.cnblogs.com/rosee-1224/p/5167879.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/357704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【APICloud系列|33】通过程序循环数据集合的时候闭包加入imageCache方法

导读:一般实现的两种思路 1、通过程序循环数据集合的时候闭包加入imageCache方法。 2、通过递归数据集合实现 发现都不是我理想的效果,数据集合量较大的时候imageCache处理的时间比不用imageCache展示的时间要慢很多,展示会有明显延迟,最终采取以下方法 还是for循环将html拼…

Linux最危险的几个命令

Linux最危险的几个命令 Linux最危险的几个命令危险命令介绍删除文件和目录命令rmLinux 的 dd 命令mkfs 格式化硬盘分区shutdown> fileMore Linux最危险的几个命令 仅个人想法,会持续不间断更新和改进。 Linux系统中的命令最美妙也最危险。 如果几个操作系统&…

Java无处不在:使用DukeScript在任何地方运行一次编写

在相当长一段时间内,Java都未能兑现“一次编写,随处运行”的承诺。 DukeScript希望通过在跨平台应用程序中实现视图和逻辑的清晰分离来改变这种状况。 在本文中,一个简单的场景用于介绍DukeScript的基础。 多年来,Java Swing使开…

数据仓库建设中的数据建模方法(转)

简介: 本文的主要内容不是介绍现有的比较流行的主要行业的一些数据模型,而是将笔者在数据仓库建设项目中的一些经验,在这里分享给大家。希望帮助大家在数据仓库项目建设中总结出一套能够合乎目前业界规范的,满足大部分行业数据仓库…

PAT 1065 A+B and C (64bit) (20)

1065. AB and C (64bit) (20) 时间限制 100 ms内存限制 65536 kB代码长度限制 16000 B判题程序 Standard作者 HOU, QimingGiven three integers A, B and C in [-263, 263], you are supposed to tell whether AB > C. Input Specification: The first line of the input gi…

十大有用但又偏执的Java编程技术

经过一段时间的编码(以我为例,大约20年左右,当您玩得开心时光飞逝),人们开始接受这些习惯。 因为,你知道... 任何可能出错的事情都会发生。 这就是为什么人们会采用“防御性编程”的原因,即偏执…

NGUI 3.5教程(二)Label 标签 (Hello world)、多行文本

写在前面: 本文将创建NGUI的第一个样例。依照编程传统,第一个样例,就是做一个Hello world 显示出来。NGUI。我们用Label来实现 。欢迎大家纠错、拍砖!原创非常辛苦,如有转载,请注明出处:htt…

linux下php可以实现哪些功能,基于Linux的远程管理系统的设计与实现(PHP)

基于Linux的远程管理系统的设计与实现(PHP)来源:2BYSJ.cn 资料编号:2SJ260700 资料等级:★★★★★ %D7%CA%C1%CF%B1%E0%BA%C5%A3%BA2SJ260700以下是资料介绍,如需要完整的请充值下载. 本资料已审核过,确保内容和网页里介绍一致. 密 惠1.无需…

tostring 16进制_ToString:身份哈希码的十六进制表示形式

tostring 16进制我以前在方便的Apache Commons ToStringBuilder上写过博客,最近有人问我,在生成的String输出中出现的看似神秘的文本是什么构成的。 询问该问题的同事正确地推测出他正在查看的是哈希码,但与他的实例的哈希码不匹配。 我解释说…

前端工程师应该掌握哪些技能才方便找工作?

作为前端工程师,必须掌握到一定的技能才方便找工作,找高薪工作,你需要掌握这些技能。 高清思维导图下载:https://download.csdn.net/download/weixin_41937552/14752706 目录 HTML5+CSS3 移动Web网页开发

延迟分析中的案例研究:锁定与同步

特别是在这篇文章中,我们将讨论: java.concurrent.Lock创建的垃圾 比较锁与同步 如何以编程方式测量延迟 争用对锁和同步的影响 协调遗漏对延迟测试的影响 回到我最喜欢的主题之一,垃圾创建/分配。 有关此主题的更多详细信息&#xff0…

思维脑图——数据分析实战(最新版)

导读:数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。 在统计学领域,将数据分析划分为描述性统计分析、探索性数据分析以及验证性数据分析,探索性数据分析侧重于在数据之中发现新的特征,而验证…

java实现一个旅游网站

导读:采用JSP和Java语言以及html脚本语言,同时采用B/S模式,进行各个界面和每个功能的设计与实现,后台管理与设计选用了SQL Server 2005数据库,前台设计与后台管理相结合,共同完成各功能模块的功能。 目录 基本功能 项目结构 项目截图

【收藏】Android屏幕适配全攻略(最权威的Google官方适配指导)

来源:http://blog.csdn.net/zhaokaiqiang1992 更多:Android AutoLayout全新的适配方式, 堪称适配终结者 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了And…

精通推荐算法1:为什么需要推荐系统(系列文章,建议收藏)

作者简介: 腾讯算法研究员。硕士毕业于中国科学院大学。在阿里和腾讯工作多年,拥有丰富的搜索和推荐算法经验。CSDN博客专家,原创文章100篇。发表专利15个,其中已授权6个。 系列文章,欢迎关注 精通推荐算法1&#x…

spring 开发环境_设置Spring 3开发环境

spring 开发环境本教程简要说明了如何设置典型的环境来开发基于Spring的应用程序。 除了可以正常工作的Windows XP客户端具有足够的CPU能力和内存外,本教程没有其他先决条件。 在教程中,我们将需要安装以下组件: Java 6 JDK更新26 适用于Jav…

Java+SSM+Oracle+Navicat+Eclipse+Microsoft Visio实现网上招聘系统

导读:整体基于B/S架构,采用MyBatis框架,运用Java中的Servlet、Jsp等关键技术,并结合Oracle数据库的使用,为招聘者和求职者搭建了一个高效、便利的网络平台。本系统分别为求职者和招聘者提供了信息注册功能,登录功能和信息维护功能。除此之外,求职者可以选择发布、撤销或…

友盟U-share sdk 分享的接入(支持Android及IOS)

导读:公司的原生开发的APP有块功能原来需要分享小程序到微信,现在改成分享成H5的形式,携带的参数不讨论,这里记录一下。 官方文档:https://developer.umeng.com/docs/128606/detail/129137 安卓分享H5:https://developer.umeng.com/docs/128606/detail/193883#h2-u5206u4E…

javaScript中const,var,let区别与用法详解

业务场景:今天想从正则表达式数组对象取出几个参数的值,发现好多人都用的const声明的变量,这里一起总结一下吧。 上一篇——》前端使用正则表达式获取地址栏URL参数的值并将需要的参数值展示在页面 场景: 查阅相关资料,总结一下js中三种定义变量的方式const, var, let的…

使用Java和Spring构建现代Web应用程序

使用Spring Framework创建Java Web应用程序从未如此简单。 如果您已经熟悉Java并且几乎没有创建Web应用程序的经验,或者如果您担心所有很酷的孩子都放弃Java取而代之的是Ruby和Node.js,那么您想读这篇。 我的意图是在此处提供实用指南,以快速…