# Consumed parameters
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中,为什么self
在init
方法中是一个consumed parameter?
这个问题我之前是不知道的,它来源于这个提问。init
方法被标记为ns_consumes_self
。ns_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的更多相关文章
- 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 ...
- 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 ...
- 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 ...
- Unity: Passing Constructor Parameters to Resolve
In this tutorial we will go through of couple different ways of using custom constructor parameters ...
- C#编程:SqlCommand.Parameters.Add()方法的参数问题。
在存储过程中添加2个参数 sql语句 例: “update [tablename] username = @username where id=@id” 然后把需要的 command.Paramete ...
- Parameter index out of range (2 > number of parameters, which is 1)
今天在实现一个功能时遇到一个问题,解决了很久.结果是#{}与${}使用错误的原因.但是具体原因还不是很清楚,写此篇总结,知道的可以交流. 具体描述为:通过教师的头衔(1高级讲师2首席讲师)及名称进行模 ...
- java中获取接口(方法)中的参数名字(eclipse设置编译参数)(java8 javac -parameters)
interface接口参数 jdk1.7及以前使用spring功能实现的: 注意: 1.该功能只能获取类的方法的参数名,不能获取接口的方法的参数名. public static void test() ...
- Content has been consumed
if(response.getEntity() != null && response.getEntity().getContent() != null) { message = IO ...
- ios AFNetworking 3.0 报错 : *** Assertion failure in -[AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:],
AFNetWorking[:] *** Assertion failure -- :::] *** Terminating app due to uncaught exception 'NSInter ...
随机推荐
- springmvc+mybatis 做分页sql 语句
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-// ...
- Spring3中@Value注解的使用
Spring可以通过@Value注解来直接获取properties文件里面配置的值. 1. 首先要在spring的配置文件中指明properties文件的位置: <context:propert ...
- 浅谈身为小白学习Linux系统的四点实用建议
游戏.办公.安全,可以总结为是方便当代人们在生活中的刚需,我们大都是这些服务的使用者,而把单个功能整合起来那就必须谈到互联网,自然而然通过互联网要将Service发送给Service manageme ...
- 或许你不知道的10条SQL技巧(转自58沈剑原创)
这几天在写索引,想到一些有意思的TIPS,希望大家有收获. 一.一些常见的SQL实践 (1)负向条件查询不能使用索引 select * from order where status!=0 and s ...
- JS - dateFormat
// date必填, pattern默认'yyyy-MM-dd HH:mm:ss'function dateFormat (date, pattern) { var week = {'0':'日', ...
- poj 1161 Walls
https://vjudge.net/problem/POJ-1161 题意:有m个区域,n个小镇,有c个人在这些小镇中,他们要去某一个区域中聚会,从一个区域到另一个区域需要穿墙,问这些人聚到一起最少 ...
- PC-lint集成于SourceInsight 范例以及简单分析;提高代码的健壮性;
写代码之际突然想起了pc-lint这个"古董级"的代码静态分析工具; 下午机房的服务器歇菜了,没法调试游戏,刚好抽出时间来研究一下pc-lint集成在SourceInsight ...
- poj_1845: Sumdiv
题目链接 先将A^B分解质因数,可以通过先分解A,再把对应的幂次*B.之后用下面这个式子求解就可以了 #include<vector> #include<iostream> u ...
- 关于EasyUI中DataGrid控件的一些使用方法总结
一,DataGrid 控件的工作流程 1,通过JavaScript将一个空白的div美化成一个空白的Datagrid模板 2,Datagrid模板通过制定的Url发送请求,获取数据 ...
- TypeScript--变量及类型的那些事儿
变量(类型)声明 格式:关键字 变量名称:类型=值 (强类型) / 关键字 变量名称=值 例子: Array数组声明 Tuple元组类型 声明一个包含多类型的数组: Enum枚举类 ...