下面代码中, “printf("%lu\n",[mstr retainCount]); // retain 1 copy 无穷大 asign 无穷大” 这一行的输出结果,可以看到有内存泄露, 其原因为?
//下面代码实在MRC模式下运行的
#import <Foundation/Foundation.h>
@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 无穷大
//上述输出都是 name是retain的情况下,若name是copy或者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
不知总结的是否正确,以后深入学习了再回头看