内存管理概述
- 内存管理
内存的作用:存储数据.
如何将数据存储到内存之中.
声明1个变量.然后将数据存储进去.当数据不再被使用的时候,占用的内存空间如何被释放.
-
内存中的五大区域
栈: 局部变量. 当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收.
堆: OC对象.使用C函数申请的空间.
BSS段: 未初始化的全局变量、静态变量. 一旦初始化就回收 并转存到数据段之中.
数据段: 已经初始化的全局变量、静态变量. 直到程序结束的时候才会被回收.
代码段: 代码. 程序结束的时候,系统会自动回收存储在代码段中的数据.栈、BSS段、数据段、代码段存储在它们中的数据的回收,是由系统自动完成的.不需要我们干预.
-
分配在堆区中的OC对象,是肯定需要被回收的.
iPhone 内存机制.
40M 警告
45M 警告
120M 闪退.存储在堆中的OC对象,系统不会自动回收. 直到程序结束的时候才会被回收.
内存管理的范围:
只需要管理存储在堆中的OC对象的回收.其他区域中的数据的回收是系统自动管理的.-
对象应该什么时候被回收?
当有人使用这个对象的时候,这个对象就千万不能回收.
只有在没有任何人使用这个对象的时候,才可以回收. -
引用计数器
1). 每1个对象都有1个属性.叫做retainCount.叫做引用计数器. 类型是unsigned long 占据8个字节.
引用计数器的作用: 用来记录当前这个对象有多少个人在使用它.
默认情况下,创建1个对象出来 这个对象的引用计数器的默认值是1.2). 当多1个人使用这个对象的时候.应该先让这个对象的引用计数器的值+1 代表这个对象多1个人使用.
3). 当这个对象少1个人使用的时候.应该先让这个对象的引用计数器的值-1 代表这个对象少1个人使用.
4). 当这个对象的引用计数器变为0的时候.代表这个对象无人使用. 这个时候系统就会自动回收这个对象.
-
如何操作引用计数器.
1). 为对象发送1条retain消息. 对象的引用计数器就会加1. 当多1个人使用对象的时候才发.
2). 为对象发送1条release消息.对象的引用计数器就会减1. 当少1个人使用对象的时候才发.
3). 为对象发送1条retainCount消息. 就可以去到对象的引用计数器的值.
就这样++ -- 当对象的引用计数器变为0的时候,对象就会被系统立即回收.
在对象被回收的时候.会自动调用对象的dealloc方法.
-
内存管理的分类
MRC: Manual Reference Counting 手动引用计数.手动内存管理.
当多1个人使用对象的时候,要求程序员手动的发送retain消息.少1个人使用的时候程序员手动的发送relase消息.
2011年之前 iOS5之前
ARC: Automatic Reference Counting 自动引用计数.自动内存管理.
系统自动的在合适的地方发送retain relase消息.
第一个MRC程序(这个简单知道就行了)
-
iOS5开始. Xcode4.2开始就支持ARC
Xcode7 默认支持ARC开发.
默认使用的开发方式就是ARC的模式.关闭ARC开启MRC.
-
当对象的引用计数器变为0的时候,系统会自动回收对象.
在系统回收对象的时候.会自动的调用对象的dealloc方法.重写dealloc方法的规范:
必须要调用父类的dealloc方法. 并且要放在最后一句代码. -
测试引用计数器.
1). 新创建1个对象,这个对象的引用计数器的值默认是1.
2). 当对象的引用计数器变为0的时候.对象就会被系统立即回收 并自动调用dealloc方法.
3). 为对象发送retain消息 对象的引用计数器就会+1 为对象发送release消息.并不是回收对象.而是让对象的引用计数器-1
当对象的引用计数器的值变为0的时候.对象才会被系统立即回收.
内存管理原则
-
内存管理的重点
1). 什么时候为对象发送retain消息.
当多1个人使用这个对象的时候,应该先为这个对象发送retain消息.
2). 什么时候为对象发送release消息.
当少1个人使用这个对象的时候.应该为这个对象发送1条release消息.
在ARC机制下,retain release dealloc这些方法无法调用.
-
内存管理的原则
1). 有对象的创建,就要匹配1个release
2). retain的次数和release的次数要匹配.
3). 谁用谁retain. 谁不用谁release.
谁负责retain 谁就负责relase4). 只有在多1个人用的时候才retain 少1个人使用的时候才release
有始有终,有加就有减. 有retain就应该匹配1个release 一定要平衡.
野指针与僵尸对象
-
野指针
C语言中的野指针: 定义1个指针变量.没有初始化.这个指针变量的值是1个垃圾值,指向1块随机的空间.这个指针就叫做野指针.
OC中的野指针: 指针指向的对象已经被回收了.这样的指针就叫做野指针.
-
对象回收的本质.
内存回收的本质:
申请1个变量,实际上就是向系统申请指定字节数的空间.这些空间系统就不会再分配给别人了.
当变量被回收的时候,代表变量占用的字节空间从此以后系统可以分配给别人使用了.
但是字节空间中存储的数据还在.回收对象:
所谓的对象的回收,指的是对象占用的空间可以分配给别人.
当这个对象占用的空间没有分配给别人之前 其实对象数据还在. -
僵尸对象
1个已经被释放的对象,但是这个对象所占的空间还没有分配给别人.这样的对象叫做僵尸对象.我们通过野指针去访问僵尸对象的时候.有可能没问题 也有可能有问题.
当僵尸对象占用的空间还没有分配给别人的时候.这是可以的.
当僵尸对象占用的空间分配给了别人使用的时候 就不可以. -
我们认为只要对象称为了僵尸对象,无论如何 都不允许访问了.
就希望如果访问的是僵尸对象,无论如何报错.僵尸对象的实时检查机制.可以将这个机制打开. 打开之后. 只要访问的是僵尸对象,无论空间是否分配 就会报错.
-
为什么不默认打开僵尸对象检测.
一旦打开僵尸对象检测 那么在每访问1个对象的时候 都会先检查这个对象是否为1个僵尸对象,
这样是极其消耗性能的. -
使用野指针访问僵尸对象会报错. 如何避免僵尸对象错误..
当1个指针称为野指针以后.将这个指针的值设置nil
当1个指针的值为nil 通过这个指针去调用对象的方法(包括使用点语法)的时候.不会报错. 只是没有任何反应.
但是如果通过直接访问属性 -> 就会报错. 无法复活1个僵尸对象.
单个对象的内存管理
-
内存泄露.
指的是1个对象没有被及时的回收.在该回收的时候而没有被回收
一直驻留在内存中,直到程序结束的时候才回收. -
单个对象的内存泄露的情况.
1). 有对象的创建,而没有对应的relase
2). retain的次数和relase的次数不匹配.
3). 在不适当的时候,为指针赋值为nil
4). 在方法中为传入的对象进行不适当的retain
-
如何保证单个对象可以被回收
1). 有对象的创建 就必须要匹配1个relase
2). retain次数和release次数一定要匹配.
3). 只有在指针称为野指针的时候才赋值为nil
4). 在方法中不要随意的为传入的对象retain.
多个对象的内存管理
-
当属性是1个OC对象的时候. setter方法的写法.
将传进来的对象赋值给当前对象的属性,代表传入的对象多了1个人使用,所以我们应该先为这个传入的对象发送1条retain消息 再赋值.
当当前对象销毁的时候.代表属性指向的对象少1个人使用. 就应该在dealloc中relase
代码写法:
- (void)setCar:(Car *)car { _car = [car retain]; } - (void)dealloc { [_car release]; [super dealloc]; }
当属性是1个OC对象的时候,setter方法照着上面那样写,其实还是有Bug的.
-
当为对象的这个属性多次赋值的时候.就会发生内存泄露.
发生泄露的原因: 当为属性赋值的时候, 代表旧对象少1个人用.新对象多1个人使用.
应该relase旧的 retain新的.-(void)setCar:(Car *)car { [_car release]; _car = [car retain]; }
@property参数
-
在MRC的开发模式下.1个类的属性如果是1个OC对象类型的.那么这个属性的setter方法就应该按照下面的格式写.
- (void)setCar:(Car *)car { if(_car != car) { [_car release]; _car = [car retain]; } } 还要重写dealloc方法. - (void)dealloc { [_car release]; [super delloc]; } 如果属性的类型不是OC对象类型的.不需要像上面那样写. 还是像之前那样写就OK了.
-
@property
1). 作用
a. 自动生成私有属性.
b. 自动生成这个属性的getter setter方法的声明.
c. 自动生成这个属性的getter setter方法的实现.特别播报:
生成的setter方法的实现中,无论是什么类型的,都是直接赋值. -
@property参数.
1). @property可以带参数的.
@property(参数1,参数2,参数3......)数据类型 名称;
2). 介绍一下@property的四组参数.
a. 与多线程相关的两个参数.
atomic、nonatomic.b. 与生成的setter方法的实现相关的参数.
assign、retain.c. 与生成只读、读写相关的参数
readonly readwrited. 是与生成的getter setter方法名字相关的参数.
getter setter -
介绍与多线程相关的参数.
atomic: 默认值. 如果写atomic,这个时候生成的setter方法的代码就会被加上一把线程安全锁.
特点: 安全、效率低下.
nonatomic: 如果写nonatomic 这个时候生成的setter方法的代码就不会加线程安全锁.
特点: 不安全,但是效率高.建议: 要效率. 选择使用nonatomic 在没有讲解多线程的知识以前 统统使用nonatomic
-
与生成的setter方法的实现相关的参数.
assign: 默认值 生成的setter方法的实现就是直接赋值.
retain: 生成的setter方法的实现就是标准的MRC内存管理代码.
也就是. 先判断新旧对象是否为同1个对象 如果不是 release旧的 retain新的.当属性的类型是OC对象类型的时候,那么就使用retain
当属性的类型是非OC对象的时候,使用assign.千万注意:
retain参数.只是生成标准的setter方法为标准的MRC内存管理代码 不会自动的再dealloc中生成relase的代码.
所以, 我们还要自己手动的在dealloc中release -
与生成只读、读写的封装.
readwrite: 默认值.代表同时生成getter setter
readonly: 只会生成getter 不会生成setter -
生成getter、setter方法名称相关的参数.
默认情况下.@property生成的getter setter方法的名字都是最标准的名字.
其实我们可以通过参数来指定@property生成的方法的名字.getter = getter方法名字
用来指定@property生成的getter方法的名字.
setter = setter方法名字
.用来指定@property生成的setter方法的名字. 注意.setter方法是带参数的 所以要加1个冒号.记住:如果使用getter setter修改了生成的方法的名字.
在使用点语法的时候.编译器会转换为调用修改后的名字的代码.修改生成的getter setter方法名字. 因为默认情况下生成的方法的名字已经是最标准的名字了.
所以.一般情况下不要去改.
1). 无论什么情况都不要改setter方法的名字. 因为默认情况下生成的名字就已经是最标准的了.
2). 什么时候修改getter方法的名字.当属性的类型是1个BOOL类型的时候.就修改这个getter的名字以is开头 提高代码的阅读性.
------总结-------
与多线程相关的参数: 用nonatomic
与生成的setter方法实现相关的参数
属性的类型是OC对象的时候 使用retain
属性的类型是非OC对象的时候 使用assign只读 读写.
如果你希望生成的封装是只读封装 那么就使用readonly
如果希望读写封装 readwrite1). 无论什么情况都不要改setter方法的名字. 因为默认情况下生成的名字就已经是最标准的了.
2). 什么时候修改getter方法的名字.当属性的类型是1个BOOL类型的时候.就修改这个getter的名字以is开头 提高代码的阅读性.
------使用参数注意-----
同1组参数只能使用1个.
getter setter可以同时使用.-
参数的顺序可以随意.
@class
当两个类相互包含的时候. 当Person.h中包含Book.h 而Book.h中又包含Person.h
这个时候,就会出现循环引用的问题. 就会造成无限递归的问题,而导致无法编译通过.-
解决方案:
其中一边不要使用#import引入对方的头文件.
而是使用@class 类名; 来标注这是1个类.这样子就可以在不引入对方头文件的情况下,告诉编译器这是1个类.在.m文件中再#import对方的头文件.就可以使用了.
-
@class与#import的区别
1). #import是将指定的文件的内容拷贝到写指令的地方.
2). @class 并不会拷贝任何内容. 只是告诉编译器,这是1个类,这样编译器在编译的时候才可以知道这是1个类.
循环retain
当两个对象相互引用的时候.
A对象的属性是B对象 B对象的属性是A对象.
这个时候 如果两边都使用retain 那么就会发生内存泄露.解决方案: 1端使用retain 另外1端使用assign 使用assign的那1端在dealloc中不再需要release了.
自动释放池(了解)
自动释放池的原理.
存入到自动释放池中的对象,在自动释放池被销毁的时候.会自动调用存储在该自动释放池中的所有对象的release方法.
可以解决的问题:
将创建的对象,存入到自动释放池之中. 就不再需要手动的relase这个对象了.
因为池子销毁的时候 就会自动的调用池中所有的对象的relase。
自动释放池的好处: 将创建的对象存储到自动释放池中,不需要再写release
如何创建自动释放池.
@autoreleasepool
{
}
这对大括弧代表这个自动释放池的范围.
如何将对象存储到自动释放池之中
在自动释放池之中调用对象的autorelease方法.就会将这个对象存入到当前自动释放池之中.
这个autorealse方法返回的是对象本身. 所以,我们可以这么写
@autoreleasepool
{
Person *p1 = [[[Person alloc] init] autorelease];
}
这个时候,当这个自动释放池执行完毕之后,就会立即为这个自动释放池中的对象发送1条release消息.
目前为止,我们感受到得autorelase的好处:
创建对象,调用对象的autorelase方法 将这个对象存入到当前的自动释放池之中.
我们就不需要再去relase 因为自动释放池销毁的时候 就会自动的调用池中所有对象的relase
使用注意
1). 只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池之中.
如果只是将对象的创建代码写在自动释放之中,而没有调用对象的autorelease方法.是不会将这个对象存储到这个自动释放池之中的.
2). 对象的创建可以在自动释放池的外面,在自动释放池之中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池之中.
3). 当自动释放池结束的时候.仅仅是对存储在自动释放池中的对象发送1条release消息 而不是销毁对象.
4). 如果在自动释放池中,调用同1个对象的autorelease方法多次.就会将对象存储多次到自动释放池之中.
在自动释放池结束的时候.会为对象发送多条release消息.那么这个是就会出现僵尸对象错误.
所以,1个自动释放池之中,只autorelease1次,只将这个对象放1次, 否则就会出现野指针错误.
5). 如果在自动释放池中,调用了存储到自动释放中的对象的release方法.
在自动释放池结束的时候,还会再调用对象的release方法.
这个时候就有有可能会造成野指针操作.
也可以调用存储在自动释放池中的对象的retain方法.
6). 将对象存储到自动释放池,并不会使对象的引用计数器+1
所以其好处就是:创建对象将对象存储在自动释放池,就不需要在写个release了.
7). 自动释放池可以嵌套.
调用对象的autorelease方法,会讲对象加入到当前自动释放池之中
只有在当前自动释放池结束的时候才会像对象发送release消息.
autorelease的规范.
0). 创建对象,将对象存储到自动释放池之中. 就不需要再去手动的realse。
1). 类方法的第1个规范:
一般情况下,要求提供与自定义构造方法相同功能的类方法.这样可以快速的创建1个对象.
2). 我们一般情况下,写1个类. 会为我们的类写1个同名的类方法,用来让外界调用类方法来快速的得到1个对象.
规范:使用类方法创建的对象,要求这个对象在方法中就已经被autorelease过了.
这样,我们只要在自动释放池中, 调用类方法来创建对象, 那么创建的对象就会被自动的加入到自动释放中.
提供1个类方法来快速的得到1个对象.
规范
a. 这个类方法以类名开头. 如果没有参数就直接是类名 如果有参数就是 类名WithXX:
b. 使用类方法得到的对象,要求这个对象就已经被autorelease过了.
-(instancetype)person{ return [[[self alloc] init] autorelease]; }
这样,我们直接调用类方法.就可以得到1个已经被autorelease过的对象.
@autoreleasepool
{
Person *p1 = [Person person];
//这个p1对象已经被autorelase过了.不需要再调用autorelase
//这个p1对象就被存储到当前自动释放池之中.
}//当自动释放池结束.就会为存储在其中的p1对象发送release消息.
实际上Apple的框架中的类也是遵守这个规范的.
通过类方法创建的对象都是已经被autorelease过的了.
所以,我们也要遵守这个规范. 类方法返回的对象也要被autorealse过.
以后,我们凡事创建对象是调用类方法创建的对象 这个对象已经是被autorelease过的了.
arc机制概述
什么是ARC
Automatic Reference Counting,自动引用计数. 即ARC.
顾名思义:系统自动的帮助我们去计算对象的引用计数器的值,
可以说是WWDC2011和iOS5引入的最大的变革和最激动人心的变化.
ARC是新的LLVM3.0
编译器的一项特性,使用ARC,可以说一举解决了广大iOS开着所憎恨的手动管理内存的麻烦.
在程序中使用ARC非常简单,只需要像往常那样编写代码.
只不过永远不要写retain、release、autorelease
永远要手动的调用dealloc
这三个关键字就好,这是ARC的最基本的原则.
当ARC开启时, 编译器会自动的在合适的地方插入retain、release、autorelase
代码.
编译器自动为对象做引用计数. 而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC).
需要特别注意的是: ARC是编译器机制. 在编译器编译代码的时候,会在适时的位置加入retain、release和autorealse代码.
ARC机制下,对象何时被释放
本质: 对象的引用计数器为0的时候,自动释放.
表象: 只要没有强指针指向这个对象,这个对象就会立即回收.
强指针与弱指针.
强指针: 默认情况下,我们声明1个指针 这个指针就是1个强指针.
我们也可以使用__strong来显示的声明这是1个强指针.
Person *p1; 这是1个强指针. 指针默认情况下都是1个强指针.
__strong Person *p2;
这也是1个强指针.使用__strong
来显示的声明强指针.
弱指针: 使用__weak标识的指针就叫做弱指针.
无论是强指针还是弱指针,都是指针,都可以用来存储地址,这1点没有任何区别 。
都可以通过这个指针访问对象的成员.
唯一的区别就是在ARC模式下.他们用来作为回收对象的基准.
如果1个对象没有任何强类型的指针指向这个对象的时候,对象就会被立即自动释放
确认程序是否开启ARC机制.
1).默认情况下,Xcode开启ARC机制.
2).ARC机制下,不允许调用retain、relase、retainCount、autorelease方法.
3).在dealloc中 不允许[super dealloc];
演示第1个ARC案例
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1个强指针.
//因为我们说过,每1个指针变量默认情况下都是1个强指针变量.
NSLog(@"------");
}//当执行到这里的时候.p1指针被回收,那么Person对象就没有任何
//强指针指向它了. 对象就在这被回收.
return 0;
}
第一个arc程序
ARC下的单个对象的内存管理.
在ARC的机制下: 当1个对象没有任何的强指针指向它的时候 这个对象就会被立即回收.
1). 当指向对象的所有的强指针被回收的时候,对象就会被立即回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1个强指针.
Person *p2 = p1;//p2也是个强指针.p1和p2都指向Person对象.
//因为我们说过,每1个指针变量默认情况下都是1个强指针变量.
NSLog(@"------");
}//当执行到这里的时候.p1指针被回收,p2指针也被回收.那么Person对象就没有任何
//强指针指向它了. 对象就在这被回收.
return 0;
}
2).将所有指向对象的强指针赋值为nil的时候.对象就会被立即回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Person *p1 = [Person new];//p1是1个强指针.
//因为我们说过,每1个指针变量默认情况下都是1个强指针变量.
p1 = nil;//当执行到这句话的时候.p1赋值为nil.
//p1指针不再执行Person对象.
//Person对象没有被任何的指针所指向,所以.Person对象在这里被释放.
NSLog(@"------");
}
return 0;
}
这两种情况就叫做没有任何强指针指向对象.
1). 指向对象的所有强指针被回收掉
2). 指向对象的所有的强指针赋值为nil
强指针与弱指针.
1). 强指针与弱指针的声明.
默认情况下,所有的指针都是强类型的,也就是说我们之前声明的指针变量都是强类类型的
p1指针是强类型的,因为默认情况下指针都是强类型的.
Person *p1 = [[Person alloc] init];
不过我们可以使用__strong来显示的标识指针是强类型指针.
__strong Person *p2 = [Person new];
这个时候p2指针类型是强指针类型的.其实写不写__strong都是强类型的指针.
指针类型也可以是弱指针类型.
使用__weak标识指针的类型是弱类型指针.
__weak Person *p3 = p2;
这个时候,p3指针就是1个弱类型的指针. p3弱指针也指向p2指针指向的对象.
在操作对象的时候,通过强指针或者弱指针都可以操作,没有任何区别.
2). ARC模式下的对象回收标准
ARC机制下释放1个对象的标准是: 没有任何强指针指向对象的时候,对象就会被释放.
如果这个时候有弱指针指向,也会被释放.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//使用strong来标识p1指针是强类型的,其实不写strong也是强类型的.
__strong Person *p1 = [[Person alloc] init];
//使用__weak标识指针p2的类型是弱类型指针.
__weak Person *p2 = p1;
//这个时候,p2指针和p1指针都指向Person对象.
//这个时候如果设置p1的值为nil
p1 = nil;
//这个时候Person对象只有被1个弱指针p2指向,没有任何强指针指向
//所以Person对象在这里被回收.
}
return 0;
}
3).最重要的1点:不能创建对象用1个弱指针存储这个对象的指针.
这样的话,刚创建出来的对象,就没有任何强指针指向,创建出来就会被回收.
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//创建1个对象,将这个对象的地址赋值给1个弱指针
//后果就是创建出来的这个对象没有被任何强指针指向.
//刚创建出来就会被释放.
__weak Person *p1 = [[Person alloc] init];
}
return 0;
}
4). 在ARC机制下. 当对象被回收的时候. 原来指向这个对象的弱指针会被自动设置为nil
arc机制下的多个对象的内存管理
ARC机制下的对象的回收的标准: 当没有任何强类型的指针指向对象的时候,这个对象就会被立即回收.
强类型指针 弱类型指针.
-
什么情况下叫做对象没有强指针向指向.
1). 指向对象的强指针被回收.
2). 指向对象的强指针被赋值为nil
-
在ARC的机制下,@property参数不能使用retain
因为retain代表生成的setter方法是MRC的标准的内存管理代码.
而我们在ARC的机制下 不需要这些代码.所以,在ARC机制下的setter方法 什么都不需要做.直接赋值就可以了.
-
ARC机制下,我们关注的重点.
当1个类的属性是1个OC对象的时候.这个属性应该声明为强类型的还是弱类型的.
很明显,应该声明为1个强类型的.问题来了?
如何控制@property生成的私有属性,是1个强类型的还是1个弱类型的呢?
使用参数, strong和weak
@property(nonatomic,strong)Car *car;
代表生成的私有属性_car 是1个强类型的.@property(nonatomic,weak)Car *car;
代表生成的私有属性_car 是1个弱类型的.如果不写,默认是strong.
-
使用建议.
1). 在ARC机制下.如果属性的类型是OC对象类型的.绝大多数场景下使用strong
2). 在ARC机制下.如果属性的类型不是OC对象类型的.使用assign3). strong和weak都是应用在属性的类型是OC对象的时候. 属性的类型不是OC对象的时候就使用assign.
在ARC机制下,将MRC下的retain换位strong
@property(nonatomic,strong)Car *car;
做的事情:
1). 生成私有属性.并且这个私有属性是strong
2). 生成getter setter方法的声明
3). 生成getter setter方法的声明setter的实现:直接赋值.
ARC 循环引用
在ARC机制下.当两个对象相互引用的时候.如果两边都使用strong 那么就会先内存泄露.
解决方案: 1端使用strong 1端使用weak
@property 参数总结
开发程序分为ARC和MRC
-
与多线程相关的参数.
atomic : 默认值 安全,但是效率低下.
nonatomic: 不安全,但是效率高.无论在ARC还是在MRC都可以使用.
使用建议: 无论是ARC还是MRC 都使用nonatomic -
retain:
只能用在MRC的模式下.代表生成的setter方法是标准的内存管理代码.
当属性的类型是OC对象的时候.绝大多数情况下使用retain. 只有在出现了循环引用的时候1边retain 1边assign assign:
在ARC和MRC的模式下都可以使用assign.
当属性的类型是非OC对象的时候 使用assign.strong:
只能使用在ARC机制下. 当属性的类型是OC对象类型的时候,绝大多数情况下使用strong]
只有出现了循环引用的时候, 1端strong 1端weak-
weak:
只能使用在ARC机制下. 当属性的类型是OC对象的时候. 只有出现了循环引用的时候, 1端strong 1端weak
-
readonly readwrite
无论是ARC还是MRC 都可以使用.
setter getter 无论在ARC下还是在MRC下都可以改.
在ARC机制下.原来使用retain的用strong
出现循环引用的时候. MRC: 1边retain 1边assign ARC: 1边strong 1边weak
MRC与ARC的兼容
-
有可能会遇到的问题.
程序使用的是ARC机制开发的,但是其中的某些类使用的是MRC.
使用命令. ` -fno-objc-arc
补充
- ARC机制和垃圾回收机制的区别.
GC: 程序在运行的期间,有1个东西叫做垃圾回收器.不断的扫描堆中的对象是否无人使用.
Person *p1 = [Person new];
p1 = nil;
ARC: 不是运行时. 在编译的时候就在合适的地方插入retain......
插入的代码足以让对象无人使用的时候 引用计数器为0