黑马程序员-内存管理之autorelease和ARC机制
一.autorelease
之前我们都是手动release对象,但是有时候我们需要延迟release对象,这里我们就需要用到autorelease,系统会把当前对象放在当前的autorelease pool中,当autorelease pool销毁时,会把当前池子中的所有对象做一次release操作。对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这些池子都是以栈结构的形式存在,在每一个Runloop结束时,当前栈顶的池子会被销毁,所有对象做一次release操作。
1.autorelease的基本用法
1> 会将对象放到一个自动释放池中
2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3> 会返回对象本身
4> 调用完autorelease方法后,对象的计数器不变
2.autorelease的好处
1> 不用再关心对象释放的时间
2> 不用再关心什么时候调用release
3.autorelease的使用注意
1> 占用内存较大的对象不要随便使用autorelease
2> 占用内存较小的对象使用autorelease,没有太大影响
4.错误写法
1> alloc之后调用了autorelease,又调用release
@autoreleasepool
{
// 1
Person *p = [[[Person alloc] init] autorelease];
// 0
[p release];
}
2> 连续调用多次autorelease
@autoreleasepool
{
Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
5.自动释放池
1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
6.自动释放池的创建方式
1> iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release]; // [pool drain];
2> iOS 5.0 开始
@autoreleasepool
{
}
下面是示例代码:
1 #import <Foundation/Foundation.h> 2 3 @interface Person : NSObject 4 @property (nonatomic, assign) int age; 5 6 + (id)person; 7 8 + (id)personWithAge:(int)age; 9 10 @end
1 #import "Person.h" 2 3 @implementation Person 4 5 + (id)person 6 { 7 return [[[self alloc] init] autorelease]; 8 } 9 10 + (id)personWithAge:(int)age 11 { 12 Person *p = [self person]; 13 p.age = age; 14 return p; 15 } 16 17 - (void)dealloc 18 { 19 NSLog(@"%d岁的人被销毁了", _age); 20 21 [super dealloc]; 22 } 23 @end
1 #import "Person.h" 2 3 @interface GoodPerson : Person 4 5 @property (nonatomic, assign) int money; 6 7 @end
#import "GoodPerson.h" @implementation GoodPerson @end
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 #import "GoodPerson.h" 4 5 int main() 6 { 7 @autoreleasepool { 8 Person *p = [Person personWithAge:100]; 9 10 11 GoodPerson *p2 = [GoodPerson personWithAge:10]; 12 13 p2.money = 100; 14 } 15 return 0; 16 }
注意问题:
1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的,例如以下2个例子。
NSString *str = @"123123";
NSString *str2 = [NSString stringWithFormat:@"age is %d", 10];
下面调用了对象方法,需要release操作
NSNumber *num = [[NSNumber alloc] initWithInt:10];
[num release];
2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
1> 创建对象时不要直接用类名,一般用self
+ (id)person
{
return [[[self alloc] init] autorelease];
}
二.ARC机制
ARC机制是IOS5所引入的,英文全称Automatic Reference Counting,自动引用计数,即ARC。有了ARC我们就不需要来手动操作内存管理的引用计数了,像retain,relesase,autorelease关键字都禁止使用。ARC全程帮我们管理内存,少了很多代码,也不用担心内存泄露。
ARC的特点:
1.ARC特点
1> 不允许调用release、retain、retainCount、autorelease
2> 允许重写dealloc,但是不允许调用[super dealloc]
3> @property的参数
* strong :成员变量是强指针(适用于OC对象类型)
* weak :成员变量是弱指针(适用于OC对象类型)
* assign : 适用于非OC对象类型
4> 以前的retain改为用strong
2.ARC的判断准则:只要没有强指针指向对象,就会释放对象。
下面代码是不使用ARC和使用ARC的区别。
创建一个Person类。
非ARC
1 #import <Foundation/Foundation.h> 2 3 @class Dog; 4 5 @interface Person : NSObject 6 7 @property (nonatomic, retain) Dog *dog; 8 9 @property (nonatomic, retain) NSString *name; 10 11 @property (nonatomic, assign) int age; 12 13 @end
1 #import "Person.h" 2 3 @implementation Person 4 5 - (void)dealloc 6 { 7 NSLog(@"Person is dealloc"); 8 9 [_dog release]; 10 [_name release]; 11 12 [super dealloc]; 13 } 14 15 @end
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 #import "Dog.h" 4 5 int main() 6 { 7 Dog *d = [[Dog alloc] init]; 8 Person *p = [[Person alloc] init]; 9 p.dog = d; 10 [p release]; 11 [d release]; 12 13 return 0; 14 }
使用ARC后代码变成了如下:
1 #import <Foundation/Foundation.h> 2 3 @class Dog; 4 5 @interface Person : NSObject 6 7 @property (nonatomic, strong) Dog *dog; 8 9 @property (nonatomic, strong) NSString *name; 10 11 @property (nonatomic, assign) int age; 12 13 @end
1 #import "Person.h" 2 3 @implementation Person 4 5 // 如果要重写dealloc,禁止写最后的[super dealloc]; 6 - (void)dealloc 7 { 8 NSLog(@"Person is dealloc"); 9 10 // [super dealloc]; 11 } 12 13 @end
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 #import "Dog.h" 4 5 int main() 6 { 7 Dog *d = [[Dog alloc] init]; 8 Person *p = [[Person alloc] init]; 9 p.dog = d; 10 11 return 0; 12 }
很明显的变化就是使用了ARC机制后禁止调用release、retain、retainCount、autorelease关键字,原来的retain用strong来代替,重写dealloc方法时禁止调用[super dealloc]