objc arc中的未知探索

ARC or not?
Automatic Reference Counting是objc发展以来相当重要的一个进步

对于开发者,任何能降低开发难度,简化代码的功能,我们都应该去了解和使用。
我们应该利用一切“偷懒”的机会,将软件开发的复杂度分解并控制在一个个小的范围内,使得对于分解后的每一个小的任务,都能被新手掌握和维护。

基于简化开发的思想来看,ARC绝对是一个没理由拒绝的技术进步。
ARC随着iOS5问世,到现在iOS8都快出了,你还在手动写retain,release么?除了固守思想外,对ARC的恐惧大都来自对它的未知。
比如我在公司尝试说服team使用ARC时被质疑的几个问题:

ARC和Java的GC一样,会导致一部分性能损耗?

首先,ARC和GC是两码事,ARC是编译时编译器“帮你”插入了原本需要自己手写的内存管理代码,而非像GC一样运行时的垃圾回收系统

ARC内存不知道什么时候释放,导致不可控的内存涨落?

了解ARC的原理后,就知道,ARC下编译器插入的内存管理的代码是经过优化的,对于使用完的内存,多运行一行代码都不会浪费,可以这么说,手写的内存管理必须达到很严谨的水平才可能达到ARC自动生成的一样完整且没有疏漏

ARC下面自己不管理内存,很不爽,很没有安全感

这纯粹是习惯的问题了,开发者的目标是用最简化的手段完成一个最可靠的程序,进步需要改变的。好在编译选项中提供了-fobjc-arc和-fno-objc-arc来保证整个的变革的继续下去,就像社会主义中国里的港澳

ARC的约定

使用ARC之后一个费解的地方是,一个方法生成的对象,没有任何附加标示,ARC怎么知道生成的对象是不是autorelease的呢?

@interface Sark : NSObject+ (instancetype)sarkWithMark:(NSString *)mark; // 1- (instancetype)initWithMark:(NSString *)mark; // 2@end

这是非ARC时常用的手段,1生成autorelease对象,2生成普通对象,而现在ARC不能调用autorelease,使用时怎么能知道呢?

{    // ...    Sark *sark1 = [Sark sarkWithMark:@"萨萨萨"];    Sark *sark2 = [[Sark alloc] initWithMark:@"萨萨萨"];}

使用约定,NS定义了下面三个编译属性

#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))

这三个属性是Clang自己使用的标示,除非特殊情况不要自己使用,但是这些对理解ARC是很有帮助的。
这里还要介绍一个概念,Method family

An Objective-C method may fall into a method family, which is a conventional set of behaviors ascribed to it by the Cocoa conventions.

指的是命名上表示一类型的方法,比如- init和- initWithMark:都属于init的family
于是乎,编译器约定,对于alloc,init,copy,mutableCopy,new这几个家族的方法,后面默认加NS_RETURNS_RETAINED标识;而其他不指名标识的family的方法默认添加NS_RETURNS_NOT_RETAINED标识
ps;iOS开发交流技术群:欢迎你的加入 ,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长
也就是说刚才的方法,在编译器看来是这样的:

@interface Sark : NSObject+ (instancetype)sarkWithMark:(NSString *)mark NS_RETURNS_NOT_RETAINED; // 1- (instancetype)initWithMark:(NSString *)mark NS_RETURNS_RETAINED; // 2@end

这也就是为什么ARC下面,不能把一个属性定义成名字是这样的:

@property (nonatomic, copy) NSString *newString; // 编译器不允许
  • newString就成了new家族的方法,内存就不对了
    对于NS_RETURNS_INNER_POINTER这货,主要使用在返回的是一个对象的内部C指针的情况,如NSString的方法:

  • (__strong const char *)UTF8String NS_RETURNS_INNER_POINTER;

就使用了这个标识,这个就不深入研究了,直接上文档:

An Objective-C method returning a non-retainable pointer may be annotated with the objc_returns_inner_pointer attribute to indicate that it returns a handle to the internal data of an object, and that this reference will be invalidated if the object is destroyed. When such a message is sent to an object, the object’s lifetime will be extended until at least the earliest of:
the last use of the returned pointer, or any pointer derived from it, in the calling function or
the autorelease pool is restored to a previous state.

全部评论

相关推荐

03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本 ACM银 go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技 ai服务中台方向 笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技 搞AI的,一面OC猎豹移动 搞AIGC方向 一面OC北京七牛云 搞AI接口方向 一面OC上海古德猫宁 搞AIGC方向 二面OC上海简文 面试撞了直接拒深圳图灵 搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节 具体业务不方便透露也是AIGC后端方向2.28约面 (不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面 一小时 半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12 二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决 给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受: 因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务