内存管理(mrc、arc):
注意:我们会用到很多的工具,包括代码,不要迷信这些工具和代码,最终你的内存是否被正常释放了,还是要靠你自己的脑子算
一、OC内存管理的原理
1、OC内存管理管的是引用计数
2、当引用计数大于0的时候,一个对象可用
3、当引用计数减到0的时候,一个对象会自动调用自己的dealloc的方法释放
4、当对一个对象执行alloc、retain、copy、new等操作时,引用计数会增加1
5、当对一个对象执行release、autorelease、self.属性名=nil等操作时,引用计数会减少1
二、OC内存管理的使用规则
1、需要为每一个alloc、retain、copy、new等+1,准备相应的-1
2、哪个类+1的,哪个类-1
3、如果是类方法创建的对象,那么会有一个自动的+1,同样这个+1的-1是自动的,不需要我们手动控制
4、如果把一个对象放进一个集合,那么这个对象会有一个自动+1,同样这个+1的-1是自动的,不需要我们手动控制
5、可以在一个+1后面加上autorelease,这样当这个对象出了自动释放池后,就是调用这个autorelease来-1
三、OC内存管理实用
1、关注当前类有多少个alloc、retain、copy、new等+1,要为他们准备对应数量的release等-1
2、不需要关注别的类的内存管理,每个类自己管自己的
3、一个类多个方法,每个方法管自己的
4、+1的数要等于-1的数
5、如果是属性,只有retain和copy需要管理,在该类的dealloc中self.属性名=nil相当于-1
四、release和dealloc区别
release 是-1 dealloc 是释放
五、内存管理举例
以people类为例
1、people类中.h文件的写法
#import <Foundation/Foundation.h>
@interface People : NSObject
@property(nonatomic,assign)NSString *name;
//assign就是指一下,不影响引用计数
@property(nonatomic,retain)NSString *sex;
//retain,指向一个对象的时候,会使得被指的对象+1,当他又指向别的对象的时候,对原来指的那个对象-1,对新指的对象+1
@property(nonatomic,copy)NSString *age;
//copy,指向一个对象的时候,把这个对象的内容拿过来,自己+1,不影响被指的对象的引用计数,指向新的对象时,先把自己-1,在把新对象的内容拿过来,自己+1
-(void)eat;
@end
2、people类中.m文件的写法
#import "People.h"
@implementation People
dealloc这个方法不是必须要实现的,也永远不要用你的对象来直接调用这个方法,这个方法在这个类的对象的引用计数减到0的时候,会自动调用,即使我们这里没有实现,也会被调用,我们之所以在这里实现,是因为我们有时候在这个类的对象被释放的时候,我们需要干点别的事儿,这些别的事儿,就写在这个方法里
-(void)dealloc
{
NSLog(@"我死了");
//[self.sex release];//retain的属性会有一个+1,这个+1最终在这个类的对象被释放的时候-1
self.sex = nil;//这个表达式,其实干了两件事,一个是对self.sex 执行release-1,同时对self.sex 指nil
self.age = nil;
//必须要写
[super dealloc];
}
-(void)eat
{
NSLog(@"又吃啊");
}
@end
3、AppDelegate.m文件中写法
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
People *lily = [People alloc];
//OC管理内存实际上管理的一段内存的引用计数
NSLog(@"%d",[lily retainCount]);
[lily eat];
[lily retain];//retain后引用计数会+1
NSLog(@"%d",[lily retainCount]);
[lily eat];
[lily retain];
NSLog(@"%d",[lily retainCount]);
[lily eat];
[lily release];//release后引用计数会-1
NSLog(@"%d",[lily retainCount]);
[lily eat];
[lily release];
NSLog(@"%d",[lily retainCount]);
[lily eat];
[lily release];
//sleep(15);
//NSLog(@"%d",[lily retainCount]);已经减到0了,会自动调用这个类的dealloc方法
//[lily eat];这个不能再被执行了,因为lily已经死了
//当引用计数减少到0的时候,这个对象就被释放了
[self classMethod];//因为classMethod是这个类的-方法,应该被这个类的对象调用,在这个类面self就是这个类的对象
[self setCondition];
[self autoReleaseMethod];
六、一个类属性的内存管理
1、assign,就是一个弱引用,就是一个指针,只是简单的指了一下,通过它可以使用他指的那个对象,但是他一点也不影响他指的对象的引用计数。如果这个assign属性指的对象引用计数大于0,这个属性就还能用,反之,这个属性就不能用。
People *polly = [People alloc];
polly.name = @"bird";
[polly release];
2、retain,retain会使得他指的那个对象的引用计数+1,所以我们需要在这个retain属性所在类的dealloc方法中对这个属性执行self.属性名 = nil;的-1操作
People *hanmeimei = [People alloc];
hanmeimei.sex = [NSString stringWithFormat:@"%@",@"female"];
[hanmeimei release];
3、copy,copy会有一个引用计数+1,所以我们需要在这个copy属性所在类的dealloc方法中对这个属性执行self.属性名 = nil;的-1操作
People *lilei = [People alloc];
lilei.age = @"18";
[lilei release];
return YES;
}
-(void)classMethod
{//如果一个对象不是用alloc方法申请的内存,而是用类方法申请的内存
NSString *str = [NSString stringWithFormat:@"%d",5];
//用类方法创建的对象,同样会有一个1的引用计数,不过这个引用计数不需要我们手动-1,他会在这个对象出了其生命周期之后,自动-1
NSLog(@"%@",str);
}
-(void)setCondition
{//当出现了集合的时候
NSString *str = [[NSString alloc] initWithFormat:@"%d",1];//str手动1
NSArray *arr = [NSArray arrayWithObjects:str, nil];//arr自动1,str一共2 手动1
//当一个对象放进数组等集合的时候,这个对象的引用计数会有一个自动+1,这个+1同样不需要手动-1,当这个对象从集合中移除掉或者这个集合本身被释放的时候,这个自动的+1就会自动的被-1
[str release];
}
-(void)autoReleaseMethod
{
@autoreleasepool {
//autorelease自动引用计数-1
NSString *str = [[[NSString alloc] initWithFormat:@"%d",4] autorelease];
//这种autorelease的引用计数-1,不是实时的,这个autorelease的原则是这个对象出了所在的自动释放池,才会调用这个autorelease进行-1
}
}