iOS 笔记

iOS与OS X多线程和内存管理(一)内存管理

2018-08-22  本文已影响227人  丁宝2012

前言

读完《iOS与OS X多线程和内存管理》有一段时间了,当时是和《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法 》一起学习的,个人认为这两本书中有很多相辅相成的东西 ,很适合一起学习,现在有空闲时间,就想把之前粗略的笔记进行一下简单的整理,主要是书中的内容整理和总结,如有理解错误的地方,希望大家指出,我们一起学习和探讨~

心得

内存管理的内容建议先阅读《iOS与OS X多线程和内存管理》中的内容,个人认为讲解的很详细和深入,阅读完以后建议配合《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法 》中的内存管理再次深入,这只是个人学习上的一点建议,希望对大家有帮助

内容

D343490EFA176479A39517E2F1F74686.jpg

cocoa框架中Foundation框架类库中NSObject类来负责内存管理

一、自己生成的对象,自己所持有

使用以下名称开头的方法(并且方法名遵守驼峰式拼写法),‘自己生成的对象只有自己持有’;调用该方法的调用者也意味着‘自己生成并持有对象’

alloc 
id obj = [[NSObject alloc]init];

new 
id obj = [NSObject new];

copy

mutableCopy

//下列名称也意味着自己生成并持有对象
allocMyObject
newThatObject
copyThis
mutablCopyYourObject
//不属于同一类别的方法
allocated
newer
copying
mutableCopyed

二、非自己生成的对象,自己也能持有

使用除alloc、new、copy、mutableCopy以外的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者,但是可以通过retain方法取得对象的持有权

id obj = [NSMutableArray array];//取得的对象存在,但自己不持有对象
[obj retain];//取得对象的持有权

三、不再需要自己持有的对象时释放

注:自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放使用release方法

取得对象的持有权方式(包含释放):

/*
 * 通过alloc/new/copy/mutableCopy等方法‘自己生成并持有对象’
 */

 id obj = [[NSObject alloc] init];//自己持有对象
[obj release];  //释放对象 

/*
 * 通过alloc/new/copy/mutableCopy等开头的自定义方法‘自己生成并持有对象’
 */

-(id)allocObject{
     id obj = [[NSObject alloc] init];//自己持有对象
    return obj;
}

//取得非自己生成并持有对象
 id obj1 = [obj0 allocObject];//因为allocObject符合命名规则,所以意味着‘自己生成并持有对象’
[obj release]; //释放对象 
/*
 * 通过alloc/new/copy/mutableCopy等方法以外的方法‘取得非自己生成并持有对象’
 */
 id obj = [NSMutableArray array];//取得的对象存在,但自己不持有对象
[obj retain];//通过retain方法,自己持有对象  
[obj release]; //释放对象 
/*
 * 通过alloc/new/copy/mutableCopy等开头以外的自定义方法‘取得非自己生成并持有对象’
 */
-(id)object{
     id obj = [[NSObject alloc] init];//自己持有对象
    [obj autorelease];//取得的对象存在,但自己不持有对象,使用NSMutableArray类的array类方法等可以取得谁都不持有的对象,同时通过‘autorelease实现的’
    return obj;
}

 id obj1 = [obj0 object];//因为object不符合命名规则,所以意味着‘取得的对象存在,但自己不持有对象’
[obj1 retain];//也能通过retain方法将调用autorelease方法取得的对象变为自己持有;  
[obj release];  //释放对象 

四、非自己持有的对象无法释放

可以并需要释放对象的情况

不可以释放对象的情况

   id obj = [[NSObject alloc] init];
  [obj release];
  [obj release];
  id obj1 = [obj0 object]
  [obj1 release];

五、allco/new/copy/mutableCopy实现

alloc

id obj =[NSObject alloc]
/*
* alloc方法实现
* 通过allocWithZone:类方法调用NSAllocateObject函数分配了对象
* NSAllocateObject函数通过调用NSZoneMalloc函数来分配存放对象所需的内存空间,之后将内存空间置0,最后返回作为对象而使用的指针
* 执行alloc后对象的retainCount=1(不考虑其他因素,只执行alloc后通过[obj retainCount]方法获取的值)
*/
+(id)alloc{
   return [self allocWithZone : NSDfaultMallocZone()];
}
+(id) allocWithZone:(NSZone *)z{
 return NSAllocateObject(self , 0 ,z);
}

疑惑点
1、 NSAllocateObject函数通过调用NSZoneMalloc函数来分配存放对象所需的内存空间,之后将内存空间置0,最后返回作为对象而使用的指针

总结

六、autorelease

5C0271E3-A893-4691-8D09-7AF019CF912B.png
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
  id obj = [[NSObject alloc]init];
  [obj release];
  [pool drain];//废弃NSAutoreleasePool对象,相当于 [obj release];
/*
* autorelease实例方法的本质就是调用NSAutoreleasePool对象的addObject类方法
* addObject类方法调用正在使用的NSAutoreleasePool对象的addObject实例方法(如果嵌套生成或持有NSAutoreleasePool对象,使用最内侧的对象)
* 调用NSObject类的autorelease实例方法,该对象将被追加到正在使用的NSAutoreleasePool对象中的数组中
*/
  [obj autorelease];
  
-(id)autorelease{
  [NSAutorelesaePool addObject:self];
}

// addObject类方法:
+(id)addObject:(id) anObj{
  NSAutorelesaePool *pool = 取得正在使用的NSAutorelesaePool对象;
  if(pool != nil){
      [pool addObject:anObj];
  }else{
     //NSAutorelesaePool对象非存在状态下调用autorelease;
  }
}

 //NSAutoreleasePool对象的addObject实例方法
-(id)addObject:(id)anObj{
   [array addObject: anObj]  ;
 }

//通过drain实例方法废弃正在使用的NSAutoreleasePool对象过程(数组中所有的对象都调用了release实例方法)
-(void)drain{
    [self dealloc];
}
-(void)dealloc{
    [self emptyPool];
    [array release];
}
-(void) emptyPool{
    for(id obj in array){
        [obj release];
  }
}

总结

  id array = [NAMutableArray arrayWithCapacity:1];
  //等同与以下代码
  id array =[[[NAMutableArray alloc] initWithCapacity:1] autorelease] ;
  [NSAutorelease showPools];

七、ARC规则

所有权修饰符

_strong修饰符

id obj = [[NSObject alloc] init];
//等价于
id _strong obj = [[NSObject alloc] init];
/*
* 情况一
*/
id obj = [[NSObject alloc] init];
//等价于
id obj = [[NSObject alloc] init];//ARC无效时

/*
* 情况二
*/
id _strong obj = [[NSObject alloc] init];
//等价于
id obj = [[NSObject alloc] init];
[obj release];//为了释放生成并持有的对象,增加调用了release方法
//obj0持有对象A的强引用
id obj0 = [[NSObject alloc] init];/*对象A*/
//obj1持有对象B的强引用
id obj1 = [[NSObject alloc] init];/*对象B*/
/*
* obj0持有由obj1赋值的对象B的强引用
* 因为obj0被赋值,所以原先持有的对对象A的强引用失效
* 对象A的持有者不存在,因此废弃对象A
* 此时持有对象B的强引用的变量为obj0 和obj1
*/
obj0 = obj1;

_weak修饰符

{
//test0持有Test对象A的强引用
id test0 =[[Test alloc] init];/*对象A*/
//test1持有Test对象B的强引用
id test1 =[[Test alloc] init];/*对象A*/
/*
* Test对象A的obj_成员变量持有Test对象B的强引用
* 此时持有Test对象B的强引用变量为test1、Test对象A的obj_
*/
[test0 setObject: test1];

/*
* Test对象B的obj_成员变量持有Test对象A的强引用
* 此时持有Test对象A的强引用变量为test0、Test对象B的obj_
*/
[test1 setObject: test0];
}
/*
* 因为test0变量超出其作用域,强引用失效,自动释放Test对象A
* 因为test1变量超出其作用域,强引用失效,自动释放Test对象B
* 此时持有Test对象B的强引用变量为Test对象A的obj_
* 此时持有Test对象A的强引用变量为Test对象B的obj_
* 内存泄露
*/

_unsafe_unretained修饰符

_autorelease修饰符

ARC规则

1、不能使用retain/release/retainCount/autorelease

2、不能使用NSAllocateObject/NSDeallocateObject

3、必须遵守内存管理的命名规则

4、不能显示调用dealloc

//ARC无效时
-(void)dealloc{
    [super dealloc];
}
//ARC有效时(ARC会自动处理,ARC有效不能显示调用dealloc所以不必书写 [super dealloc])
-(void)dealloc{
 
}
-(void)dealloc{
   [ [NSNotificationCenter defaultCenter] removeObserver:self];
}

八、属性

@property (nonatomic , strong) NSString * name;
F7DC6FC7-543A-4E23-9673-9294EA918EF5.png
/*
*错误举例
*/
/声明id型obj成员变量
id obj;

//定义其属性声明为weak
@property (nonatomic , weak) id obj;

/*
*正确举例1
*/
/声明id型obj成员变量
id   _weak obj;

//定义其属性声明为weak
@property (nonatomic , weak) id obj;


/*
*正确举例2
*/

//声明id型obj成员变量
id  obj;

//定义其属性声明为strong
@property (nonatomic , strong) id obj;

九、数组

十、ARC实现

_strong修饰符

_weak修饰符

上一篇 下一篇

猜你喜欢

热点阅读