iOS 内存管理
内存管理的原理
iOS 内存管理,是基于引用计数来管理内存;当对象引用计数为0时,对象将被销毁,回收内存空间;内存管理的法则是谁持有的,谁负责释放;
1. 自己生成的对象,自己持有
2.非自己生成的对象也能持有
3.不需要自己持有自己持有对象时,需要释放
4.无法释放非自己持有的对象
内存管理的两种模式
iOS内存管理分为两种模式:MRC和ARC
最开始内存管理,程序员需要自己管理对象的引用计数,就是我们熟知的MRC
后来苹果进行的改革,采用ARC模式,在编译阶段,自动对代码优化,加入release 的释放内存的操作,解放了程序员,当然这是简单的理解;其实还涉及到运行时的一些内容,我们可以简单从ARC要从以下两方面支持可以了解到:
1. clang(LLVM编译器)3.0以上
2.objc4 Objective-C运行时库493.9以上
影响引用计数的几种方式
1. 导致引用计数加1
alloc、new、copy、mutableCopy 这几个关键操作会产生一个新的对象,引用计数为1
retain:MRC下的操作,会使对象的引用计数加1
在ARC ,用一个强引用指针指向一个NSObject对象,会导致NSObject对象的引用计数加1
id __strong obj = [[NSObject alloc] init]; // 此时 obj的引用计数为1
id __strong obj1 = obj; // 此时obj的应用计数为2
2.引用计数减1
release: 当然这是MRC下才能使用了
3.不会对引用计数产生变化
weak 、assign修饰的变量,两者区别weak修饰对象释放后指针指向nil,assign则不然,另外assign可以修饰一些字面量;
ARC 的一些规则
不能使用retain、release、retainCount、autorelease方法
不能使用NSAllocateObject、NSDeallocateObject函数
不要显式调用dealloc
使用@autoreleasepool块代替NSAutoreleasePool
需遵守内存管理命名规则
1)alloc、new、copy、mutableCopy等以这些名字开头的方法都应当返回调用方能够持有的对象2)init开头的方法必须是实例方法并且要返回对象,返回值要是id或者该方法对应类的对象类似或者其超类或者其子类。另外,init开头的方法也仅仅用作对对象进行初始化操作
不能使用区域(NSZone)
对象型变量不能作为C语言结构体的成员
显式转换"id" 和 "void*"
循环引用
聊到内存,无法避免聊到循环引用
循环引用的实质:多个对象相互之间有强引用,不能释放让系统回收。
如何解决循环引用:
1. 避免产生循环引用,通常是将 strong 引用改为 weak 引用。
2. 在合适时机去手动断开循环引用。
几种常见的循环引用
1. 代理(delegate)循环引用属于相互循环引用
delegate 是iOS中开发中比较常遇到的循环引用,一般在声明delegate的时候都要使用弱引用 weak,或者assign,当然怎么选择使用assign还是weak,MRC的话只能用assign,在ARC的情况下最好使用weak,因为weak修饰的变量在释放后自动指向nil,防止野指针存在
2. NSTimer循环引用属于相互循环使用
在控制器内,创建NSTimer作为其属性,由于定时器创建后也会强引用该控制器对象,那么该对象和定时器就相互循环引用了。
如何解决呢?
这里我们可以使用手动断开循环引用:
如果是不重复定时器,在回调方法里将定时器invalidate并置为nil即可。
如果是重复定时器,在合适的位置将其invalidate并置为nil即可
3. block循环引用
并不是所有block都会造成循环引用。