现有Person类, 有属性如下:
@property(nonatomic, retain)Student *student;
@property(nonatomic, copy)NSString *name;
@property(nonatomic, copy)NSString *name;
@property(nonatomic, retain)NSString *sex;
assign下的属性内部实现:
setter:
- (void)setName:(NSString *)name{
_name = name;
}
|
getter:
- (NSString *)name{
return _name;
}
|
对于基本数据类型的属性可以使用assign修饰, 基本数据类型生成在栈空间, 其内存有系统自动管理, 我们人工无法进行管理.
对于类型属性若用assign修饰, 若在外部调用了setter, 并进行了一次释放, 则会肯能使_name指向被释放的内存空间, 有出现野指针的危险.
retain下的属性内部实现:
setter:
- (void)setName:(NSString *)name{
if (_name != name) { —> 先判断, 传过来的对象和之前的成员变量是否相等
[_name release]; —> 如果不同, _name 所指向的原来的内存空间引用计数-1, 不一定是释放! 对于刚生成的对象, 其_name成员变量为空指针, 所以release时不会造成过度释放
_name = [name retain]; —> 把新的内容赋给成员变量, 赋值前先让name引用计数+1, 防止野指针
}
}
|
getter:
- (NSString *)name{
return [[_name retain] autorelease]; —> return之前先retain一次,再autorelease一次,加减平衡. autorelease是因为,不知道外界什么时候用完,所以会等到出了释放池在release
}
|
发现:
Person *person1 = [[Person alloc] init];
Student *student1 = [[Student alloc] init];
[student1 retain];
NSLog(@"%lu", [student1 retainCount]); —> 打印结果:2
person1.student = student1; —> 将 student1 赋给 person1 中的 student 成员变量, 赋值后二者指向同一块内存空间
NSLog(@"%lu", [student1 retainCount]); —> 打印结果:3, 赋值期间, student1 所指向的内存空间引用计数 +1
[person1 release];
NSLog(@"%lu", [student1 retainCount]); —> 打印结果:3,
将person1 release后, student1所指向的内存空间引用计数并不-1, 重写dealloc方法原因即在于此! 关于dealloc, 见笔记: 8. 内存管理初级
|
copy下的属性内部实现:
setter:
- (void)setName:(NSString *)name{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
|
getter: 同 retain下的属性内部实现
在便利构造器中考虑内存管理:
+ (id)personWithName:(NSString *)name
sex:(NSString *) sex{
Person *p = [[Person alloc] initWithName:name age:age];
return [p autorelease];
}
|
因此, 使用便利构造器创建的对象不需要考虑内存管理, 因为在便利构造器内部实现已考虑内存的自动释放
关于init初始化方法小记:
何时使用不带参数的初始化方法, 即, 直接alloc?
- 在不需要在初始化时对成员变量进行赋值时, 则不带参数, 但如果有数组或字典类型的成员变量, 则一定要初始化数组或字典, 否则添加对象的操作无效(参见homework5中addressbook类中的初始化方法).