NSCopying协议的使用,setter和getter方法的作用,内存管理高级,集合的内存管理

来源:互联网 发布:php 进制转换 编辑:程序博客网 时间:2024/04/28 14:31
#import "Teacher.h"@interface Student : NSObject{    Teacher *_tea;//学生类的实例变量}@property (nonatomic, retain) Teacher *tea;//当语义属性声明为retain时,.m文件会自动生成setter方法和getter方法@property (nonatomic,copy) Teacher *tea1;@end
//属性的实现就是setter和getter方法,内部是对实例变量赋值以及取值操作,所以方法内要操作实例变量。/*-(void)setTea:(Teacher *)tea{    //判断原有对象和新对象是否是同一个,如果是同一个,就没有必要重新赋值了,否则 会先release,release之后空间被系统回收,此时再retain就成为了野指针问题    if (_tea != tea) {        [_tea release];//释放保有的之前对象的所有权,否则内存泄漏</span>        _tea = [tea retain];//让实例变量_tea保有新的对象所有权,tea在右边,所以是取值操作,得到tea指向的堆区空间的内容,把tea里面的内容赋给_tea,这样_tea就保存了一份堆区空间的所有权,从而在main.m里边防止造成野指针错误(一个alloc要对应一个release,不这样做,alloc之后引用计数就为0,堆区空间就会被回收,会造成野指针)。    }    //self.tea = tea;//死循环(点语法调用的就是自己的setter方法)
语义特性声明为copy,setter方法的内部实现- (void)setTea1:(Teacher *)tea1{    if (_tea1 != tea1) {        [_tea1 release];        //如果想对一个对象进行copy操作,对象的类必须服从一个NSCopy协议,并且实现协议中的方法        _tea1 = [tea1 copy];//调用copywithzone    }}- (Teacher *)tea{    //return self.tea;//也是死循环,调用自己的getter方法    return [[_tea retain] autorelease];}- (void)dealloc//这个dealloc是学生类的实例变量{    //当该类对象的引用计数为0时,会自动调用该类对象的dealloc方法   当调用dealloc方法时,该对象的空间将要被系统回收,将保有的其他对象的所有权给释放掉    [_tea release];//释放最后一次    [_tea1 release];//释放最后一次    [super dealloc];//调用父类方法的实现}@end
@interface Teacher : NSObject <NSCopying>{    NSString *_name;//姓名    NSString *_gender;//性别}@property (nonatomic, retain) NSString *name;@property (nonatomic, retain) NSString *gender;- (id)initWithName:(NSString *)name gender:(NSString *)gender;+ (id)teacherWithName:(NSString *)name gender:(NSString *)gender;@end</span>
//NSCopying协议的实现(服从协议的类实现这个方法)- (id)copyWithZone:(NSZone *)zone//只拷贝空间,所以还要把空间里边的内容拷贝过来,操作的是副本{    Teacher *newTea = [[Teacher allocWithZone:zone] init];//newTea本来就是个局部变量,出了这个方法,空间就被回收了,所以要在回收之前赶紧把堆区空间的地址返回给self    newTea.name = self.name;//self就是原来开辟的堆区空间    newTea.gender = self.gender;    return newTea;}- (void)sayHi{    NSLog(@"gkg,fk,");}-(void)setName:(NSString *)name{    if (_name != name) {        [_name release];        _name = [name retain];    }}-(void)setGender:(NSString *)gender{    if (_gender != gender) {        [_gender release];        _gender = [gender retain];    }}- (void)dealloc//对实例变量操作{    NSLog(@"%@空间被回收了",self.name);    [_name release];    [_gender release];    [super dealloc];}- (id)initWithName:(NSString *)name gender:(NSString *)gender{    self = [super init];    if (self) {        //_name = name;//这只是进行了简单的赋值操作,没有调用setter方法,这样的话,声明语义特性为retain就不起任何作用,没有对内存做(retain)处理,会影响后边的dealloc,所以在进行初始化的时候使用点语法会对内存做优化        self.name = name;        self.gender = gender;    }    return self;}+ (id)teacherWithName:(NSString *)name gender:(NSString *)gender{    Teacher *tea = [[Teacher alloc]initWithName:name gender:gender];    return [tea autorelease];}@end
//main.m文件Teacher *tea = [[Teacher alloc] init];//0 - 1        Student *stu = [[Student alloc] init];//0 - 1        //stu.tea = tea;//在系统内部进行赋值(因为<span style="background-color: rgb(102, 51, 255);">在等号右边,赋的值是tea这个指针变量里面的内容,堆区空间的地址)操作,引用计数不增加        stu.tea = tea;//1 - 2        NSLog(@"cxnxbzb%lu", [tea retainCount]);        [tea release];//2 - 1,tea指向的那块堆区空间的引用计数 -1        //stu.tea;//这里没有问题,因为这里仅仅是得到了stu这个对象的内容,虽然有了这块空间里的地址,但是并没有通过这个地址访问地址里面的内容,不会有野指针        [stu.tea sayHi];//这里会有野指针问题,因为通过这个空间里的地址,让地址里面的内容进行sayhi方法,但是这块空间已经被回收
collection 的内存管理//1.当把一个对象放入集合(数组,字典,集合)中时,会将对象的引用计数+1,因为内部做了retain操作        //2.当集合(数组,字典,集合),空间被回收时,他们会向容器中的每一个元素发送一次release消息,{对应添加元素时的retain操作        //3.当从collection(数组,字典,集合)中移除一个元素时,会release该对象,该对象指向的堆区空间的引用计数-1</span>


 




0 0
原创粉丝点击