内存管理的方式有三种:1.垃圾回收 2.MRC手动:引用计数的方法 3.ARC自动
内存管理的原则就是加减平衡
默认是ARC,调成MRC的方法是:在xcode中,搜索auto,找到ARC选项改成NO.引用计数retainCount在ARC下不能使用,只能在MRC下使用,而且retainCount的作用就是用来显示当前对象的引用情况,是一个参考值
改变引用计数的方法,一共六种
1.retain:就是对引用计数起+1的作用
// [stu retain];
// NSLog(@"%ld", [stu retainCount]);
// [stu retain];
// [stu retain];
// [stu retain];
// NSLog(@"%ld", [stu retainCount]); // 加上创建对象,现在的结果是5
2.release:就是对引用计数进行-1的作用,不是释放!!
// [stu release];
// NSLog(@"%ld", [stu retainCount]);
// [stu release];
// [stu release];
// [stu release];
// NSLog(@"%ld", [stu retainCount]); // 结果是1
3.alloc:也可以改变引用计数,只要对象创建出来,他的引用计数就是1,也相当于能增加引用计数
// Student *stu = [[Student alloc] init];
// // 对象的引用计数 retainCount
// NSLog(@"%ld", stu.retainCount);
4.dealloc:当对象的引用计数加和减平衡之后,该对象就要被释放了,自动调用dealloc进行对象的释放,dealloc才是释放的方法
- (void)dealloc{
NSLog(@"我被释放了");
[_name release];
[_arr release];
[_dic release];
[super dealloc];
// [super dealloc]必须写在最后一位
}
// dealloc是对象最后走的一个方法,在mrc下这个方法里主要写属性的释放
注意: 对象通过alloc进行对象的创建,并且把引用计数+1,然后通过retain和release修改引用计数,当加和减平衡时,自动调用dealloc进行对象的释放.其中alloc和dealloc功能相对,alloc和dealloc功能相对
常见的内存问题:
1.过度释放:当对象已经释放之后再对对象进行relea操作,会引起对象的过度释放,过度释放是以后常见的内存问题
2.野指针:当对象已经释放掉的时候,指针还保存着对象的地址,如果对这个对象继续操作,在UI里马上回崩溃.这种已经释放掉的对象称为野指针,野指针也是非常常见的内存问题
UI里对内存的要求更为苛刻,会直接崩溃,如果是内存问题造成的崩溃,在控制台会显示(lldb),就要找release
5.autorelease:延迟释放对象
autorelease和pool配合使用,只要对象进行autorelease的操作,系统就会把对象添加到自动释放池中,在池子范围内,对象不会改变引用计数,只要超出了池子范围,对象引用计数-1.autorelease会延迟释放对象,release会马上对引用计数进行修改
// // 自动释放池
// @autoreleasepool {
// [stu autorelease];
// NSLog(@"%ld", [stu retainCount]);
//
// }
// NSLog(@"%ld", [stu retainCount]);
什么时候需要写release:如果对象是我们用alloc创建的,需要写release.如果通过便利构造器创建的,不要写release;如果有retain就写release.系统类优先使用便利构造器和字面量,因为不需要内存管理.以后类里面有便利构造器,优先用,因为不需要对内存进行处理,用就好了
6.copy:需要<NSCopying>协议
// NSString *str = @"马云";
// NSString *newStr = [str copy];
// NSLog(@"%@", newStr);
// Student *stu = [Student studentWithName:@"afg" sex:@"m"];
// Student *newStu = [stu copy];
// NSLog(@"%@", newStu.name);
// NSLog(@"%ld", [newStu retainCount]);// 结果是1
// [newStu release];// 将新的字符串释放<pre name="code" class="objc">- (id)copyWithZone:(NSZone *)zone{
Student *stu = [Student allocWithZone:zone];
stu.name = self.name;
stu.sex = self.sex;
return stu;
} // copy方法的声明
容器对内存的影响:对象加入到容器里,为了防止对象的野指针问题,会自动给对象的引用计数+1,对象会随着数组消失而消失,或者可变数组移除对象,也可以减少对象的引用计数
// Student *stu = [[Student alloc] initWithName:@"张丹" sex:@"女"];
// NSLog(@"%ld", [stu retainCount]);
// NSArray *arr = @[stu];
// NSLog(@"%ld", [stu retainCount]); //这个时候结果是2
// [stu release];
内存与属性:copy(只用NSString使用,copy方法),retain(属性中写retain,那么setter方法可以直接使用), assign(在栈区不需要处理内存)
// set方法主要是为了防止野指针的发生
// 先对传过来的地址和成员变量的地址进行判断,看是不是同一个对象,如果是同一个对象,不做任何的操作
// 如果不是,则把成员变量之前保存的对象先-1,然后对新的值+1,把新的对象付给成员变量保存
//- (void)setPer:(Person *)per{
// 如果在属性中写了retain,那么setter方法可以直接使用
// 苹果的官方版:老值比较多,官方版比较好
// if (_per != per) {
// [_per release];
// _per = [per retain]; // 防止野指针
// }
// 另一个版本:两个版本都可以用,新值比较多,这个比较好
// [_per release];
// [per retain];
// _per = per;
//}