本文阅读建议
1.一定要辩证的看待本文.
2.本文所表达观点并不是最终观点,还会更新,因为本人还在学习过程中,有什么遗漏或错误还望各位指出.
3.觉得哪里不妥请在评论留下建议~
4.觉得还行的话就点个小心心鼓励下我吧~
在这篇文章中,我会总结最近对iOS开发内存课题的查阅和学习,文章的中心还是围绕着面试题来的。因为网上目前确实存在着很多的面试题和答案,但他们大多数都是拷贝粘贴,甚至答案都是错的。
当然,本文的答案也是仅供参考,更希望大家与我一起讨论修改。因为本文面试题过多,不再罗列所有面试题,采取循序渐进的方式讲解。
本文的用途是在于巩固复习,可能在部分之处有遗漏知识点,后期有时间将会单独抽出来去说。
这几道题从14年到16年频频出现,记得自己背的回答是OC对象采取引用计数管理,遵循“谁创建,谁释放。谁引用,谁管理”的原则
。
在iOS中,使用引用计数
来管理OC对象的内存。在iOS 5之前是MRC(手动管理引用计数),iOS 5推出了ARC(自动管理引用计数)。ARC 是 LLVM 3.0 编译器的特性,用来自动管理内存。
在MRC下,当对象调用alloc、new、copy、mutableCopy
方法会使该对象引用计数+1,在调用release
,或者autorelease
会对引用计数-1。如果一个对象的引用计数器为0,则系统就会自动调用这个对象的dealloc
方法来销毁这个对象。
在代码中,一般使用dealloc
方法来查看一个对象是否被回收,如果没有被回收,则有可能会造成内存泄露。如果确认一个对象已经被释放,那么最后需要将他的变量手动设置为nil,否则可能会造成野指针错误。
在ARC下,由系统自动管理内存,并分别用strong、weak、unsafe_unretained
修饰词代替retain、assign
,ARC会自动添加release和autorelease调用,无须手动调用。
内存大致分为保留区、代码段、数据段、堆区、栈区、内核区
代码段:编译之后的代码。
数据段:常常称为静态常量区
,其包含字符串常量、未初始化的全局/静态常量、已初始化的全局/静态常量
。
栈:函数调用开销,比如局部变量。分配的内存空间地址越来越小,由编译器来进行管理。
堆:通过alloc、malloc、calloc
等动态分配的空间,分配的内存空间地址越来越大,由开发者进行管理。
在上面问题的基础上会引出这些问题:
我是15年开始入坑iOS开发的,从Xcode 5学起,当时大多数项目还都是MRC项目,其中最有名的还数ASIHTTPRequest库,MRC下需要手动进行引用计数管理,不乏就要写大量的retain和release。ARC可以说是对程序员非常友好的一个功能。它就是为了解决书写MRC代码占用过多时间的问题。
那么ARC通过什么方式帮助开发者管理内存?这就要说起LLVM这个强大的编译器了。
前端获取你的源代码进行词法分析、语法分析、语义分析、生成中间代码;然后将它编译为某种LLVM中间代码表示这就是支持混编的原因
。后端部分可以根据平台生成实际运行的机器码。
ARC作为LLVM 3.0的一个功能,会在编译阶段自动插入retain以及release、autorelease,但清除weak引用的时候靠的是runtime,后面会讲到。ARC只负责管理Objective-c 对象的内存,CoreFoundation 对象不归ARC管理。基础数据类型不需要内存管理。
ARC都帮我们做了什么呢,下面一一列举:
修饰词说明:
atomic:修饰的对象会保证setter和getter的完整性,任何线程访问它都可以得到完整的初始化的对象。atomic比nonatomic安全,但不是绝对的线程安全。
nonatomic:修饰的对象不保证setter和getter的完整性。所以访问效率要比atomic快。
strong:表示指向并拥有该对象。其修饰的对象引用计数会加1.该对象只要引用计数不为0,就不会被销毁。
weak:表示指向但不拥有该对象。其修饰的对象引用计数不会增加。对象销毁时该指针自动置为nil。
assign:主要用于修饰基本数据类型,如NSInteger和CGFloat。在MRC下,也常用于修饰delegate。
copy:与strong类似,但内部实现不同,常用于修饰不可变对象,例如:NSString、NSArray、NSDictionary。
readwrite:这个属性是默认的情况,会自动为你生成存取器。
readonly:只生成getter不会有setter方法。
readwrite、readonly这两个属性的真正价值,不是提供成员变量访问接口,而是控制成员变量的访问权限。
在Objective-C中,基本数据类型的默认关键字为atomic,readwrite,assign;普通属性的默认关键字为atomic,readwrite和strong。
在这里推荐一篇喵神的文章-手把手教你ARC——iOS/Mac开发ARC入门和使用
经过时间的推移,这些问题不再以简单的形式出现,涉及到以下知识点:
并且也有一些比较新颖的面试题出现:
要搞清楚这些,就务必要进行Runtime
的学习
苹果开源-objc4代码列表:选择最新的,我下载的源码是objc-723。
首先我们要理清楚的就是三个概念对象本质、isa指针、struct结构体
在调用alloc或者allocWithZone:方法后,将会得到该类的
未初始化
的实例变量,alloc方法将会在应用中开辟一段空间,用于存储相关对象和数据。在将分配集设置isa
到对象的类之后,该对象将集成到继承层次结构的运行时视图和构成程序的当前对象网络(类和实例)中。因此,对象可以找到它需要的任何信息运行时,例如另一个对象在继承层次结构中的位置,其他对象符合的协议,以及它可以响应消息执行的方法实现的位置。
除了进行开辟内存外还会执行其他重要操作:
isa
实例变量指向对象的类,它是一个从类定义编译的运行时对象。nil
,NULL
和0.0
)。但是调用alloc
或者allocWithZone:
返回的对象尚不可用。需要调用初始化方法,init
必须初始化具有特定特征的对象并返回功能对象。
alloc只是单纯的返回一个未进行初始化的对象,并不能进行使用,需要进行init的操作;而new的本质是调用alloc并默认发送init消息,返回一个已经初始化的对象。如果你需要调用自定义的init的方法就不要调用new方法。new方法默认调用init。
在进行了alloc
和init
方法后,我们就可以获得对象实例了,那么什么是isa,isa指针又是如何运作的呢?
使用Xcode点到NSObject类当中,我们会发现NSObject类里包含着一个isa指针,isa指针指向类对象Class。再点一下Class,我们会发现,它是一个结构体,结构体里具体的实现就要去objc源码当中查询。
在这里先推荐一篇对我帮助颇大的文章:
如果您对这篇文章有什么意见或者建议,请评论与我讨论.
如果您觉得还不错的话~可以点个喜欢鼓励我哦.
如果您想和我一起学习,请毫不吝啬的私信我吧~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。