OC内存分析之retain与copy的简单测试示例
1、初始化Circle类的origin时可以采用以下方式:
(1)origin = [[XYPoint alloc] initWithX:_p.x andY:_p.y];
(2)origin = [_p retain];
或 origin = [_p copy];//此时,XYPoint类需要“遵循”NSCopying协议并实现协议的copyWithZone:方法,以实现深拷贝。
- (id)copyWithZone: (NSZone *)zone
{//拷贝 用已经存在的对象实例化新对象 origin=[_p copy];
XYPoint* temp = [[XYPoint alloc] initWithX:x andY:y];
return temp;
}
(3)self.origin = _p;//等价于[self setOrigin:_p];
内存分析方式取决于setOrigin:内部的实现
.如果声明属性时,赋值方式为 assign,setOrigin:内部的实现如下:
-(void)setOrigin:(XYPoint*)_p
{
origin = _p;
}
.如果声明属性时,赋值方式为 retain,setOrigin:内部的实现如下:
-(void)setOrigin:(XYPoint*)_p
{
if(origin != _p)
{
[origin release];
origin = [_p retain];
}
}
.如果声明属性时,赋值方式为 copy,setOrigin:内部的实现如下:
-(void)setOrigin:(XYPoint*)_p
{
[origin release];
origin = [_p copy];
}
eg:
XYPoint.h
#import <Foundation/Foundation.h>
//类“遵循”协议,那么类中必须要实现协议中的@required方法
//@optional
//copy 消息的接收者所属类需要“遵循”NSCopying协议,并实现协议中的copyWithZone:方法。
@interface XYPoint : NSObject<NSCopying>{
int x;
int y;
}
@property(nonatomic,assign)int x;
@property(nonatomic,assign)int y;
-(id)initWithX:(int)_x andY:(int)_y;
-(NSString*)description;
@end
XYPoint.m
#import "XYPoint.h"
@implementation XYPoint
@synthesize x,y;
-(id)initWithX:(int)_x andY:(int)_y
{
if (self = [super init]) {
x = _x;
y = _y;
}
return self;
}
//对象名.成员函数 [对象 消息];
- (id)copyWithZone:(NSZone *)zone
{//拷贝 用已经存在的对象实例化新对象 origin=[_p copy];
XYPoint* temp = [[XYPoint alloc] initWithX:x andY:y];
return temp;
}
-(NSString*)description
{
return [NSString stringWithFormat%@“(%d,%d)”,x,y];
}
@end
Circle.h
#import <Foundation/Foundation.h>
#import "XYPoint.h"
@interface Circle : NSObject{
int radius;
XYPoint* origin;
}
@property(nonatomic,assign)int radius;
@property(nonatomic,retain)XYPoint* origin;
-(id)initWithR:(int)_r andOrigin:(XYPoint*)_p;
-(NSString*)description;
@end
Circle.m
#import "Circle.h"
@implementation Circle
@synthesize radius,origin;
//
-(id)initWithR:(int)_r andOrigin:(XYPoint*)_p
{
if(self = [super init])
{
radius = _r;
// origin = [[XYPoint alloc] initWithX:_p.x andY:_p.y];//常规做法
// origin = _p;//有没有问题?有 二次删除问题
//origin = [_p retain];//修改之后的语句
origin = [_p copy];//执行过程与内存分析
// self.origin = _p;
// self.origin = [[[XYPoint alloc] init] autorelease];
}
return self;
}
-(NSString*)description
{
return [NSString stringWithFormat%@“r:%d,origin:%@",radius,origin];
}
-(void)dealloc
{//如果类中有对象实例变量,为了避免内存泄漏,可以重写dealloc
[origin release];//nil:空对象 Nil
//向空对象发送消息没有效果
[super dealloc];
}
@end
main.m(测试retain)
#import <Foundation/Foundation.h>
#import "Circle.h"
#import "XYPoint.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
//个数一致 alloc+retain+copy ==release+autorelease
XYPoint* p = [[XYPoint alloc] initWithX:1 andY:1];//p引用计数为1
Circle* c = [[Circle alloc] initWithR:1 andOrigin:p];//c引用计数为1
//测试retain
XYPoint* p1 = [p retain];//p与p1指向同一块堆空间,并且引用计数会加1 p引用计数为2
NSLog(@"%lu,%lu",[p retainCount],[p1 retainCount]);
[p release];
[c release];
}
return 0;
}
输出结果2,2
main.m(测试copy)
#import <Foundation/Foundation.h>
#import "Circle.h"
#import "XYPoint.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
XYPoint* p = [[XYPoint alloc] initWithX:1 andY:1];//p引用计数为1
Circle* c = [[Circle alloc] initWithR:1 andOrigin:p];//c引用计数为1
//测试copy
XYPoint* p1 = [p copy];//深拷贝 p与p1引用计数都为1,各自指向一块堆空间
NSLog(@"%lu,%lu",[p retainCount],[p1 retainCount]);
[p release];
[c release];
}
return 0;
}
输出结果为:1,1