#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>