consumed这个单词我并不能给出很准确的翻译,在这篇文章中,我把Consumed parameters称为耗用参数,它在OC中有着独特的应用场景。

https://clang.llvm.org/docs/AutomaticReferenceCounting.html#id7这份文档中,讲解了ARC方面的知识,我对Consumed parameters这一个小模块有很大的疑问,因此在网上查了一些资料,虽然有了一个大概的了解,但是还是有一些不太清楚的地方。

我们先来看一个例子,这个例子来源于上边的那份文档:

void foo(__attribute((ns_consumed)) id x);
- (void) foo: (id) __attribute((ns_consumed)) x;

我们可以用__attribute((ns_consumed))来修饰某个函数或者方法的参数,但这只是表面上的看法,实际上,它并不是只作用于它修饰的某个参数,而是作用于整个函数或方法。

它的一个限制是,只能修饰可retain的对象指针类型,比如id, Class等等,不能修饰int *这样的类型。

上边的两行代码表示foo被标记为consumed。意味着该函数的被调用者希望得到一个+1 retain count的对象。声明了这个属性后,当传入一个参数时,在函数调用前,ARC会把对该参数做一次retain操作,在该函数结束后再对该参数做一次release操作,这一过程很像函数对局部变量的操作。

到这里就产生了第一个疑问?

为什么要对传入的参数做retain,在结束时又release掉?

这个跟参数的生命周期有关,我们在函数中使用了参数,当然希望能够得到这个参数的所有权,并且希望该参数一直存活着。这个内容我会在下边的内容中给出一定的解释。在上边的文档中有这样一段话:

Rationale
This formalizes direct transfers of ownership from a caller to a callee.
The most common scenario here is passing the self parameter to init, but it is
useful to generalize. Typically, local optimization will remove any extra retains
and releases: on the caller side the retain will be merged with a +1 source, and on
the callee side the release will be rolled into the initialization of the parameter.

这段话指出,上边的操作直接从调用者到被调用者转移了所有权,最常见的一个场景就是传递self参数到init方法之中,这个内容将是本文最重要的内容。一般来说,局部的优化会移除任何额外的retain和release操作,这句话的意思是说,在函数中,某些局部变量不一定都会十分严格的按照retain/release原则来进行操作。调用端将会进行一些必要的合并操作,而被调用端也会对参数做一些额外的操作。

到这里,有了第二个疑问?

在ARC中,为什么selfinit方法中是一个consumed parameter?

这个问题我之前是不知道的,它来源于这个提问init方法被标记为ns_consumes_selfns_consumes_self说明在方法中遵循上边讲的原则,在方法调用之前先把self做retain操作,结束时做release操作。

User *user = [[User alloc] init];

这是一行非常简单的代码,在调用了alloc后就创建了一个User对象,这个可以在这篇回答中获得证据。返回的对象的retain count等于1,大家应该记得,凡是通过alloc/new/copy.etc生成的对象,retain count都会+1,那么在这里的init方法中:

self = [super init];
if (self) { ... }
return self;

self首先被init的调用者做了一次retain操作,此时它的retain count为1,执行完self = [super init];后,它的retain count为2,直到init返回后,self做了一次release操作,此时它的retain count为1。**这就完美保证了self在方法中是一直存活的,也保证了能够返回一个retain count为1的对象。

有兴趣可以翻看这个提问中的回答的部分,那哥们说的很详细,再说一点,在以前的MRC时代,代码可以这样写:

- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}

为了正确返回某个对象,先retain再release。

因此在使用consumed的时候,需要注意一下几点:

  • 保证方法的接收者不能为null,因为在方法被调用之前,参会会做retain操作,这样就带来了内存泄漏的问题
  • 传递的参数的个数不能大于方法能够动态处理的个数,否则可能引起未知的后果
  • 谨慎处理静态类型的问题

何为静态类型,何为动态类型?

A *a = [A new];
B *b = a;

那么b的静态类型就是B,这个类型是由编译器决定的,而A则是它的动态类型,由运行时决定。

我发现ASDisplayKit的源码极其复杂,估计要花相当多的时间来解读了。不能放弃,加油。

# Consumed parameters的更多相关文章

  1. Database Initialization Parameters for Oracle E-Business Suite Release 12 (文档 ID 396009.1)

    In This Document Section 1: Common Database Initialization Parameters For All Releases Section 2: Re ...

  2. Database Initialization Parameters for Oracle E-Business Suite Release 12

    In This Document Section 1: Common Database Initialization Parameters For All Releases Section 2: Re ...

  3. ORA-01078: failure in processing system parameters & LRM-00109: could not open parameter file

    安装了Oracle 12C后,启动数据库的过程中出现如下错误 SQL> startup ORA-01078: failure in processing system parameters LR ...

  4. Unity: Passing Constructor Parameters to Resolve

    In this tutorial we will go through of couple different ways of using custom constructor parameters ...

  5. C#编程:SqlCommand.Parameters.Add()方法的参数问题。

    在存储过程中添加2个参数 sql语句 例: “update [tablename] username = @username where id=@id” 然后把需要的 command.Paramete ...

  6. Parameter index out of range (2 > number of parameters, which is 1)

    今天在实现一个功能时遇到一个问题,解决了很久.结果是#{}与${}使用错误的原因.但是具体原因还不是很清楚,写此篇总结,知道的可以交流. 具体描述为:通过教师的头衔(1高级讲师2首席讲师)及名称进行模 ...

  7. java中获取接口(方法)中的参数名字(eclipse设置编译参数)(java8 javac -parameters)

    interface接口参数 jdk1.7及以前使用spring功能实现的: 注意: 1.该功能只能获取类的方法的参数名,不能获取接口的方法的参数名. public static void test() ...

  8. Content has been consumed

    if(response.getEntity() != null && response.getEntity().getContent() != null) { message = IO ...

  9. ios AFNetworking 3.0 报错 : *** Assertion failure in -[AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:],

    AFNetWorking[:] *** Assertion failure -- :::] *** Terminating app due to uncaught exception 'NSInter ...

随机推荐

  1. vijos1051题解

    题目: 圣诞老人回到了北极圣诞区,已经快到12点了.也就是说极光表演要开始了.这里的极光不是极地特有的自然极光景象.而是圣诞老人主持的人造极光. 轰隆隆--烟花响起(来自中国的浏阳花炮之乡).接下来就 ...

  2. # nodejs模块学习: express 解析

    # nodejs模块学习: express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子 ...

  3. Unity3D-Shader-热扭曲效果

    [旧博客转移 - 2016年1月13日 13:18 ] 前面的话: 本来我是想写一个水的原理的,但是发现涉及的知识太多,还有好多不懂的,所以就先一步一步来 最近呢,我在网上捡到了一本<热扭曲秘籍 ...

  4. springmvc(一) springmvc框架原理分析和简单入门程序

    springmvc这个框架真的非常简单,感觉比struts2还更简单,好好沉淀下来学习~ --WH 一.什么是springmvc? 我们知道三层架构的思想,并且如果你知道ssh的话,就会更加透彻的理解 ...

  5. 微信小程序选项卡功能

    首先看看微信小程序上的选项卡的效果 原理呢,就是先布局好(这就不必说了吧),然后在上面的每一个选项卡上都定义一个同样的点击事件,然后给每一个组件上绑定一个唯一的标识符,然后点击事件触发的时候,获取到绑 ...

  6. Android - Fragment (一)定义

    什么是Fragment,为什么要用Fragment? Fragment,直译为碎片.是Android UI的一种. Fragment加载灵活,替换方便.定制你的UI,在不同尺寸的屏幕上创建合适的UI, ...

  7. SLAM中的优化理论(一)—— 线性最小二乘

    最近想写一篇系列博客比较系统的解释一下 SLAM 中运用到的优化理论相关内容,包括线性最小二乘.非线性最小二乘.最小二乘工具的使用.最大似然与最小二 乘的关系以及矩阵的稀疏性等内容.一方面是督促自己对 ...

  8. opencc 繁体简体互转 (C++示例)

         繁体字通常采用BIG5编码,简体字通常采用GBK或者GB18030编码,这种情况下,直接使用iconv(linux下有对应的命令,也有对应的C API供编程调用)就行.对于默认采用utf-8 ...

  9. Java 简单的 socket 编程入门实战

    这个是给女朋友写的:) 首先需要知道我们每个电脑都可以成为server(服务器) 和 client(客户端) 我们需要使用java来实现客户端与服务器的数据传输 先帖上代码 注意这里两张代码处于两个j ...

  10. Python优缺点

    优点 简单----Python是一种代表简单主义思想的语言.阅读一个良好的Python程序就感觉像是在读英语一样,尽管这个英语的要求非常严格!Python的这种伪代码本质是它最大的优点之一.它使你能够 ...