深入内存管理

  1. alloc/new 对象分配创建后,引用计数为1
  2. retain 向对象发送retain消息,对象的引用计数+1
  3. copy 向对象发送copy消息,创建一个新的对象,其引用计数为1;原来对象的引用计数不变
  4. release 向对象发送release消息,对象内存引用计数-1,如果引用计数为0,那么系统就会立即调用dealloc方法,释放对象占有的内存
  5. autorelease 对象发送autorelease消息,对象引用计数-1;如果引用计数为0,不会马上释放对象内存,等到最近一个自动释放池autorelease时候释放。

手动内存管理规则
1. 局部(临时)变量

[supView addSubView:tmpView];
使得tmpView的引用计数+1,当supView被release的时候,父视图上面的所有子视图的引用计数都会被release一次,使子视图的引用计数-1,这样保持了retain/release的平衡。

2.

- (void)viewDidLoad {
    [super viewDidLoad];
    _cpu = [[CPU alloc] init];
}
-(void)dealloc{
    [_cpu release];
    [super dealloc];
}
alloc/init创建的对象,因为需要在整个ViewController作用域使用,所以应该在dealloc方法里发送release消息;若使用类方法(工厂模式)创建对象实例,不需在dealloc方法再向其发送release消息,这是因为类方法返回的对象已经在方法内部加入了自动释放池,其引用计数和生命周期交由自动释放池管理。

3.@property属性对象(与其他类进行交互)
访问修饰符默认是assign,根据需求可是retain或copy。
定义属性时,编译器会根据修饰关键字(assign/retain/copy)自动生成getter/setter,getter方法没区别,setter方法会有不同。

-(void)setOldObj:(id)newValue{//assign修饰符
    oldObj = newValue;
}
相当于指针赋值。对象的引用计数不发生改变。注意:当原对象oldObj不再使用,要把这个对象设置为nil
-(void)setOldObj:(id)newValue{//retain修饰符
    if(oldObj != newValue){
        [oldObj release];
        [newValue retain];//使其引用计数+1
        oldObj = newValue;//新值赋给原来的值
    }
}
注意:下面这张创建实例对象的方式易造成内存泄漏!因为在setter方法内又被retain了一次,对象的引用计数为2
self.oldObj = [[OldObj alloc]init];
改正:正确的赋值方式(1)(2)
(1)使用指针指向的方式赋值如下
OldObj *tmpOldObj = [[OldObj alloc] init];
self.oldObj = tmpOldObj;//self.oldObj的引用计数为1
[tmpOldObj release];

-(void)dealloc{
    [self.oldObj release];//释放内存空间
    [super dealloc];
}
(2)self.oldObj通过OldObj的类方法初始化创建的实例赋值方式
self.oldObj = [OldObj oldObjWithClassMethod:xxx];
由于类方法内部添加了自动释放池(延时释放),不需要手动释放但出于编码规范在dealloc时向其发送release消息
-(void)dealloc{
    [self.oldObj release];//出于编码规范
    [super dealloc];
}
-(void)setOldObj:(id)newValue{//copy修饰符
    if(oldObj != newValue){
        [oldObj release];
        oldObj = [newValue copy];
    }
}
copy是深拷贝即拷贝对象。copy修饰符就是复制一份新的赋值给oldObj,oldObj的引用计数不发生改变,newValue对象的引用计数+1

(1)self.property(属性的访问)可以兼容懒加载。self.xxx(局部变量的访问)时是调用一个getter方法。会使引用计数+1,而_xxx引用计数不会改变。同时也避免了使用下滑线的时候忽略了self这个指针,后者容易在BLock中造成循环引用。
(2)self.property换成_property简短易读,执行速度较快,spa体积更小。使用 _xxx是获取不到父类的属性,只对局部变量访问
(3)循环引用
直接用私有变量有个需要特别注意的地方,在 block 里直接写 _property 相当于 self->_property,虽然没写 self,但是暗含了对 self 的retain,容易造成循环引用。要记得用 weakSelf/strongSelf。


self.weakCmp
等效于如下代码:
- (Computer *)weakCmp
{
return [[_weakCmp retain] autorelease];
}

你可能感兴趣的:(深入内存管理)