内存管理 && 内存泄漏 && copy mutableCopy && NSArray中内容的更新

1,犯了比较傻逼的错误,记录下,以后要注意,

- (void)_onMarketQuotationReceived:(NSNotification *)notification

{

  YLBusiness *business = [notification.userInfoobjectForKey:YLNotificationKeywordBusiness];

  RspMarketQuotation *response = business.responseObject;

#warning !!! quotationTable 内存泄露

  NSArray *quotationTable = response.quotationTable.copy; //要改成[response.quotationTable.copy autorelease];

  for (YLQuotation *quotationin quotationTable) {

    if ([quotation.prod_codeisEqualToString:self.quotation.prod_code]) {

#warning !!! _quotation可能指向一个已经释放的地址

      _quotation = quotation; //因为quotation指向的内容其实是notification对象的内容,当此方法结束之后,notifation对象就会被释放,释放了之后,_quotation就指向了一个已经释放的地址,程序就挂掉了。所以解决方法是必须要把_quotation对象保留或者copy一份。见解决方法

      [self_updateView];

    }

  }

}

解决方法1:

self.quotaion = quotation;

 //因为quotaion对象是retain属性的,这样就会retain quotation对象,当notification释放的时候,虽然notification对象释放掉了,quotation也释放了,但是quotation所引用的内存是没有被释放的,因为被self.quotaion持有了,所以不会被释放。当self.quotation释放的时候,这块内存才真正的释放。

关于局部变量quotation的释放,形象的理解就是quotation指针与quotation指针所指向的内存之间的连线被砍断了,也就是notifation对象的任务完成了,它不再持有这块内存。以后谁持有,就让谁去释放。这个时候,这块内存与self.quotation之间的连线还存在着,所以这块内存的最终释放由self.quotation来负责。

解决方法2:

SAFE_RELEASE(_quotaion);//如果不释放就会造成_quotation指向的以前的内存的泄漏。

_quotation = quotation.copy;//这样就需要quotation对象实现NSCopying协议,比较麻烦

其实这里可以简单的处理

SAFE_RELEASE(_quotaion);

_quotation = [quotation retain]; //因为其实只要保证quotation不被释放就好了。并不需要copy一份副本出来。

其实可以看出解决方法2其实就是手动的实现quotaion属性的set方法,先释放再retain的过程。因此真实的项目中直接使用方法1就行了。如果_quotation只是一个成员变量并没有实现set方法就用此方法解决。



2,copy与mutableCopy的区别

copy  目的是为了创建新的对象副本,在objc中有如下区别:

不可变对象 copy  == 对象retain    (这是由于ios内存优化的原因,因为不可变对象copy创建新对象其实还是和源对象是一样的,那么分配内存的时候直接不分配了而是指向源对象retain count就+1了,所以相当于retain)

可变对象 copy      == 创建了一个新的不可变的对象

可变/不可变对象mutablecopy == 创建一个新的可变对象

有位前辈这么总结的,我觉得很好:
copy,生成的是不可变对象,无论源对象是否是可变的
mutablecopy,新对象是可变的,无论源对象是否可变


3,更新NSAray对象或者NSMutableArray对象的时候,要注意:


    Quotation *quotaion1 = [[[Quotationalloc] init]autorelease];

    quotaion1.name =@"QUO1";

    quotaion1.price =@"1.111";

    

    Quotation *quotaion2 = [[[Quotation alloc] init] autorelease];

    quotaion2.name =@"QUO2";

    quotaion2.price =@"2.2222";

    

    Quotation *quotaion3 = [[[Quotation alloc] init] autorelease];

    quotaion3.name =@"QUO3";

    quotaion3.price =@"3.3333";

    

    NSArray *quotationTable = [NSArray arrayWithObjects:quotaion1,quotaion2, nil];

    

    for (Quotation *quotation in quotationTable) {

        /*更新quotationTablequotation2元素的内容*/

        if ([quotation.name isEqualToString:@"QUO2"]) {

            quotation = quotaion3; //错误用法,这样是没有效果的,因为quotation是一个新创建的临时对象,这个对象指向的内容是quotationTable[1]。改变quotation只是改变了quotation变量本身,其实并没有改变quotationTable[1],就如同函数的实参与形参一样,只有改变quotation.name才会改变到quotationTable[1].name。所以改变quotation指向的内容才会改变quotationTable的内容。


           quotation.name = @"quotationChange";//正确用法,这样就能更新NSArray里面的内容了,NSMutableArray同样。

           quotation.price = @"2.221";//正确用法


        }

    }


4,实现NSCopying协议

@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSString *price;

- (id)copyWithZone:(NSZone *)zone
{
         MyObj *copy = [[[self class] allocWithZone:zone] init];

         self.name = _name;//之所以不使用self.name = [[_name copy] autorelease];是因为name是copy属性

         self.price = _price;

}

也可以使用方法2,效果是一样的
方法2:

- (id)copyWithZone:(NSZone *)zone
{
         MyObj *copy = [[[self class] allocWithZone:zone] init];

         copy->name = [_name copy];//这里之所以没加autorelease,是因为copy->name方式是弱引用,没有retain name,所以不能加autorelease

         copy->name = [_price copy];

  return copy;

}

可以看到方法2并没有释放copy.name以前的内存,这是因为copy对象新建的时候是直接使用的init方法,因此copy.name是没有指向任何内容的,所以才不需要释放,但是,如果新建copy对象的时候使用的是initWithObj:XXX这种方法,那么是需要释放copy的成员变量以前指向的内容的。因此有鉴于此,不要使用方法2来进行copy。


还有一种常见的情况,就是name跟price属性都是retain的情况下,如何写copy方法呢?

@property (nonatomic, retain) NSString *name;

@property (nonatomic, retain) NSString *price;

- (id)copyWithZone:(NSZone *)zone
{
         MyObj *copy = [[[self class] allocWithZone:zone] init];

         self.name = _name;//这样写在目前的情况下是没有问题的,因为对name属性copy或者retain的效果是一样的,因为name是不可变的字串。但是如果name属性是可变字串的情况下,这样写,只是对可变字串进行了retain操作,当源name的内容改变的时候,copy.name的内容也就改变了,没有达到预期的效果,因此建议使用方法3来进行copy协议,不管name是可变还还是不可变的都是适用的。

         self.price = _price;

 return copy;

}

方法3:

- (id)copyWithZone:(NSZone *)zone
{
         MyObj *copy = [[[self class] allocWithZone:zone] init];

         self.name = [[_name copy] autorelease];//如果name是可变的,那么copy之后会新开辟一块内存,以后源name改变,也不会影响copy.name了

         self.price = [[_price copy] autorelease];

 return copy;

}





你可能感兴趣的:(内存管理 && 内存泄漏 && copy mutableCopy && NSArray中内容的更新)