MRC模式下property 的retain带来的内存泄露

下面代码中,  “printf("%lu\n",[mstr retainCount]);    // retain 1   copy 无穷大    asign 无穷大”  这一行的输出结果,可以看到有内存泄露, 其原因为? 



//下面代码实在MRC模式下运行的

#import

@interface person:NSObject

{

    NSString *name;

}

@property(assign)NSString *name;

+(instancetype) newPersonWithName: (NSString *) strName;

@end


@implementation person :NSObject

@synthesize name;

+(instancetype) newPersonWithName: (NSString *) strName

{

    person* newSelf= [selfnew];

    newSelf.name=strName;              //这个代码,在本类字段name的属性为 retain的时候,会带来内存泄露...应该如何避免呢?

    return newSelf;

}

@end


int main(int argc,constchar * argv[])

{

    NSAutoreleasePool *pool=[NSAutoreleasePoolnew];

    NSMutableString *mstr=[NSMutableStringstringWithString:@"liji"];

    printf("%lu\n",[mstrretainCount]);     //retain 1   copy 1        assign 1

    person *perX=[personnewPersonWithName:mstr]; //调用了本类name属性的的Setter方法

    printf("%lu\n",[mstrretainCount]);     //retain 2   copy 1        assign 1

    printf("%lu\n",[mstrretainCount]);     //retain 2   copy 1        assign 1

    NSLog(@"%@\n",perX.name);NSLog(@"%@\n",perX.name);NSLog(@"%@\n",perX.name); //应该因为是生成了3个临时person对象,调用了3此name的setter方法

    printf("%lu\n",[mstrretainCount]);     //retain 5   copy 1        assign 1

    [pool drain];

    printf("%lu\n",[mstrretainCount]);    // retain 1   copy无穷大    asign 无穷大

    //上述输出都是 nameretain的情况下,若namecopy或者assign,则这里都是一个乱数,代表mstr内存被释放了,而用retain,这里会有内存泄露

}


原因自己分析如下,在person类的name字段的属性参数设置为retain的时候,一个类方法的定义如下:

+(instancetype) newPersonWithName: (NSString *) strName  

{

    person* newSelf= [selfnew];

    newSelf.name=strName;     

    //[strName autorelease];         //name为retain的时候,必须加上本句,否则会内存泄露         

    return newSelf;

}


在这个方法里调用了name对象的setter方法,且本方法并不在 autoreleasepool模块中,故不会自动生成一个与retain配套的release,因此,这里需要显式的添加一个autorelease调用,且要保证调用本方法的语句位于 NSAutoreleasepool模块内,这样就不会内存泄露,同时不会出现野指针。



本问题结论:

一个类的类方法中,如果用到了其字段的存取器,则一定要查看其是 retain、copy 还是assign,否则,可能会带来内存泄露或者野指针。 具体使用方式为:

     I、若是assign,则需要先调用 retain, 再调用autorelease

    II、若使retain,则需要调用 autorelease

    III、若使copy, 则需要调用 autorelease



不知总结的是否正确,以后深入学习了再回头看









你可能感兴趣的:(IOS)