内存管理
单个对象内存管理
1. 野指针错误:
访问了一块坏的内存
2. 僵尸对象:
如果一个对象已经被释放,这个对象被称为僵尸对象
3. 空指针:
没有指向任何东西的指针,给空指针发送消息不会报错
4. nil和NULL的区别
nil 对象指针
NULL 类对象指针
5. 避免使用僵尸对象的方法:
对象释放了以后,给对象赋值为nil
6. 单个对象的内存泄露
情况1: 创建完成,使用之后,没有release
情况2: 没有遵守内存管理原则
Dog *d = [[Dog alloc] init]
[d retain];
情况3: 不当的使用了nil
Dog *d = [[Dog alloc] init]
d = nil;
情况4: 在方法中对传入的对象进行了retain
Dog *d = [[Dog alloc] init]
[d compareColorWithOther: d];
基本数据类型set方法的写法 直接赋值
-(void)setSpeed:(int)speed { _speed = speed; }
对于对象作为另外一个类的实例变量
-(void)setDog:(Dog *)dog{ if(_dog!=dog){ //先判断是不是原来的对象 [_dog release]; //不是原来的对象做一次release, _dog = [dog retain]; } }
@property 参数
格式:@property (参数1,参数2) 数据类型 方法名
1.是否要生成set方法
readwrite : 同时生成setter和getter的声明、实现
readonly :只会生成getter的声明和实现
2.多线程管理
nonatomic :性能高(一般用这个)
atomic :性能低(默认)
3.set管理相关参数
retain :release旧值,return新值(适用于oc对象类型)
assign : 直接赋值(默认,适用于非OC对象)
-(void)setCar:(Car *)car{
_car =car;
}
(2) retain release旧值,再retain新值
在一个类中有关联其他对象的时候,这个对象的 @property(nonatomic,assign) 数据类型 方法名
-(void)setCar:(Car *)car{ if(_car!=car){ //先判断是不是原来的对象 [_car release]; //不是原来的对象做一次release, _car = [car retain]; } }
readonly :只读,只会生成getter的声明和实现
readwrite:默认的,同时生成setter和getter的声明和实现
(4)多线程管理
@property(nonatomic,assign) 数据类型 方法名
高性能,一般使用nonatomic
(5) set和get方法的名称
修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用 在布尔类型中的getter
//替换set方法名称 @property(nonatomic,assign ,setter= isVip:) //替换get方法名称 @property(nonatomic,assign ,getter = isVip) //替换set,get方法名称 @property(nonatomic,assign ,setter=isVip,getter = isVip:)
循环retain问题
会导致两个对象都会内存泄露
防止方法:
1) 让某一个对象多释放一次(注意顺序)
2) 推荐方法: 一端使用assign 一端使用retain
Dog.h #import <Foundation/Foundation.h> //#import "Person.h" @class Person; @interface Dog : NSObject //狗有个主人 @property (nonatomic,retain) Person *owner;//这里用retain @end Dog.m #import "Dog.h" #import "Person.h" @implementation Dog - (void)dealloc { [_owner release]; // NSLog(@"Dog dealloc"); [super dealloc]; } @end Person.h #import <Foundation/Foundation.h> //#import "Dog.h" @class Dog; @interface Person : NSObject //人拥有一条狗 @property (nonatomic,assign) Dog *dog;//这里用assign @end Person.m #import "Person.h" #import "Dog.h" @implementation Person - (void)dealloc { // [_dog release]; //nil这里不在需要 NSLog(@"Person dealloc"); [super dealloc]; } @end main.m #import <Foundation/Foundation.h> #import "Dog.h" #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [Person new]; //1 Dog *d = [Dog new]; //1 //人有一条狗 p.dog = d; // d 1 d.owner = p; // p 2 [p release]; //0 [d release]; // // [d release]; // [p release]; } return 0; }
类方法不需要管理内存
autorelease基本使用
一个对象调用autorelease,将这个对象放到位于栈顶得的释放池
@autoreleasepool
{ //
}
概念介绍: 一种支持引用计数器的内存管理方式,可以暂时保存某个对象,然后再内存池自己的排干的时候对其中的每个对象发送release消息
好处: 不用担心对象释放时间,也不用担心什么时候调用release
原理:
autorelease实质上只是把对release的调用延迟了,对于每一个autorelease,该Object放入了当前的Autoreleasepool中,当该pool释放时,该pool中的所有Object都会被调用release;
自动释放池: 特殊的栈结构(数据结构),和内存的栈区结构不同
特点: 对象可以加入到自动释放池中,自动释放池结束的时候,会给释放池中的每个对象发送一条release消息
使用:
1)自动创建释放池
autoreleasepool{
}
2)加入自动释放池,
在自动释放池中
[对象 autorelease]
加入到自动释放池中以后,引用计数器不会变化
基本用法总结
1.会将对象放到一个自动释放池中
2.当自动释放池被销毁时,会对尺子里的所有对象做一次release操作
3.会返回对象本身
4.调用完autorelease方法后,对象的计数器不变。
int main(int argc, const char * argv[]) { //1 创建自动释放池 Person *p = [Person new]; // p 1 @autoreleasepool {//自动释放池开始 [p run]; NSLog(@"%lu",p.retainCount); // 1 // [p autorelease] 把对象p加入到自动释放池中 // 注意:加入到自动释放池中以后, 引用计数不会变化 [p autorelease]; //加入自动释放池, NSLog(@"%lu",p.retainCount); // 1 [p run]; }//自动释放池结束 [p release]; [p run]; return 0; }
注意及错误用法:
1)并不是放到自动释放池中的代码产生的对象就会自动释放,如果需要释放,必须自动加入到自动释放池
2)如果对象调用了autorelease但是调用autorelease的时候,没有在任何一个自动释放池中,此时该对象也不会被加入到自动释放池
3)我们只需要在自动释放池代码块中调用autorelease就可以把对象加入到自动释放池
4)内存较大尽量不要使用autorelease
自动释放池嵌套使用
为什么内存管理只管理内存对象?
堆中内存不连续,无法自动释放!
我们如何对内存对象进行管理!
通过操作对象的引用计数器
autorelease的应用场景
经常用来在类方法中快速创建一个对象
1)判断是否是ARC机制
查看项目信息,不能使用retain release和autorelease,retainCount ,不能调用[super dealloc]
2)使用
正常创建对象,不用手动释放对象
ARC下单对象内存管理
ARC机制下,对象没有被强指针指向,对象会立即释放空间
(两个下划线)__strong 修饰的指针是强指针,可以不写
__weak 修饰的指针是弱指针
1) 强指针指向了其他内容,对于对象来说就没有强指针指向了
2) 弱指针赋值为nil
ARC下多对象的内存管理
ARC机制下不能使用retain 应该使用strong 和 weak
ARC下循环引用问题
循环引用时一端使用strong , 一端使用weak.
ARC下set方法内存和@property参数
原子性/读写 和MRC下一样
MRC ARC
assign assign 适用于非oc对象
retain strong(强指针) OC的其他对象 weak (成员变量是弱指针适用于oc对象)
copy copy
ARC使用特点及注意事项
特点:
1) 不允许调用retain release、retainCount
2) 允许重写dealloc,但是不能调用[super dealloc]
注意事项:
1)ARC中,只要弱指针对象不存在,直接把弱指针清空(赋值nil)操作
2)__weak Person *p = [Person new]
弱指针指向空间销毁过程: (1)释放对象空间 (2)指针赋值nil
MRC转换为ARC
edit->Refactor->convert to Objective-C ARC…简单代码
ARC兼容非ARC的类
转变为非ARC -fno-objc-arc
转变为ARC的 -f-objc-arc