四,关于语义特性copy和与alloc对应的dealloc以及初始化操作和便利构造器的补充

1, 语义特性copy

如果想对一个对象进行copy操作,对象的类必须服从一个NSCopying协议,并且实现协议中的方法copyWithZone:,方法为(仍以Person类为例):

-(id)copyWithZone:(NSZone*)zone

{

NSString*newSex = [[NSStringallocWithZone:zone]init];

newSex.sex = self.sex;

returnnewSex;

}

其中copyWithZone: 是协议NSCopying制定的方法,

2, dealloc

对于dealloc方法,由于系统不知道我们在开发程序时会对那些对象的语义特性声明为retain或者copy,所以需要我们重写dealloc方法,即如下:

-(void)dealloc

{

[_namerelease];

[_sexrelease];

NSLog(@"Person空间回收了");

[superdealloc];

}

(1), [_namerelease]和[_sexrelease]操作目的:当调用dealloc方法时,该对象的空间将要被系统回收,在空间回收之前,将保有的其他对象()的所有权给释放掉,当该类对象的引用计数为0时,会自动调用该类的dealloc方法

(2), [superdealloc]该操作即必须通过super调用父类的方法实现,才能将空间回收,

3, 初始化操作

-(id)initWithName:(NSString*)name sex:(NSString *)sex

{

self =[superinit];

if (self) {

self.name = name;

self.sex = sex;

}

returnself;

}

(1),使用self.name = name赋值方法,self.name时调用了setter方法,内部对name进行了retain操作,即_name也保留了name的使用权,如果使用_name = name即直接赋值方法,则就表示把属性的语义特性设为asgin,这时如果name的空间已经被回收了,直接赋值就会出现野指针问题

使用self.sex = sex同理;

(4),便利构造器

+(id)teacherWithName:(NSString*)name sex:(NSString *)sex

{

Person*person = [[Person alloc] initWithName:namesex:sex];

return [Personautorelease];

}

我们在使用便利构造器时不需要再对其进行release操作,因为内部已经做了autorelease操作,如果在进行release操作会造成过度释放,以后我们再写便利构造器就要这样写.

五,collection(集合) 的内存管理

当把一个对象放入集合(数组,字典,集合)中时,会将对象的引用计数 + 1,因为内部做了retain操作

例如:Person *per1 = [[Personalloc] initWithName:@"Frank"sex:@"boy"];

Person *per2= [[Personalloc] initWithName:@"Duke"sex:@"boy"];

此时per1和per2所指向的空间的引用计数都为1,

NSMutableArray *array =[[NSMutableArray alloc ]initWithObjects:per1,per2, nil];

这里使用便利构造器,其内部给添加到数组中的元素进行了autorelease操作,这时per1和per2所指向的空间的引用计数都为2,

当集合(数组,字典,集合)空间被回收时,他们会向容器中的每个元素发送一个release消息(对应添加元素时的retain操作),当从集合(数组,字典,集合)中移除一个元素时,会release该对象,引用计数 - 1;

下面把对该数组对象以及存储的对象的进行release操作

(1),[per1release];

[per2release];

NSLog(@"%lu",[ per1retainCount]);

NSLog(@"%lu",[ per2retainCount]);

此时 per1和per2所指向的空间的引用计数都为1, array所指向的空间的引用计数为1,

NSLog(@"%@",array); 此时会输出数组中的内容

[per1release];

[per2release];

此时per1和per2的空间都被回收,因为系统识别到他们的引用计数都为0

NSLog(@"%@",array);此时若再执行该操作系统会crash,因为数组中存储的对象已经被系统回收了,如果输出相当于又对数组中被回收的空间进行操作,是野指针问题

NSLog(@"arrayCount= %lu",[array retainCount]);

此时array所指向的空间的引用计数为1,因为array的空间没有被回收,但不可以输出数组

(2),[array release];

此时array所指向的空间被系统回收

NSLog(@"%lu",[tea1retainCount]);

NSLog(@"%lu",[tea2retainCount]);

此时per1和per2所指向的空间的引用计数都为1,

NSLog(@"%@",array);此时若再执行该操作系统会crash, 因为数组已经被回收, 如果输出相当于对被回收的数组进行操作,是野指针问题

[per1release];

[per2release];

此时per1和per2的空间都被回收,因为系统识别到他们的引用计数都为0

NSLog(@"arrayCount= %lu",[array retainCount]);

若进行此操作,会crash, 因为array的空间已经被回收


(3), [per1release];

[per2release];

此时per1和per2所指向的空间的引用计数都为1, array所指向的空间的引用计数为1,

[arrayrelease];

此时array所指向的空间被系统回收,per1和per2的空间也都被回收,当集合(数组,字典,集合)空间被回收时,他们会向容器中的每个元素发送一个release消息(对应添加元素时的retain操作),即此时per1和per2的空间都被回收,因为他们收到了release消息,