属性的属性, 是对内存的优化,! 这里具体讲解
- 属性的内部实现原理
assign
assign的内部实现 // 定义变量的时候, 无原子性, 语义设置为assign;
@property(nontatomic , assign)NSString *name;
setter 方法
- (void)setName:(NSString *)name {
_name = name;
}
getter 方法
- (NSString *)name {
return _name;
}
调用!
NSString *name = [[NSString alloc] initWithFormat:@"张三"];// 此时计数为1
Person *p = [[Person alloc] init]; p引用计数为1
[p setName:name] p指向存储name那块空间区域, p引用计数为1, name 引用计数为1;
[name release] 则name计数减1为0, 则name那块空间被释放!
NSLog:(@"%@", [p name]); p所指向的那块区域已不存在 ,p变为了野指针!也就是野指针异常 !
[p release];
所以, 当用alloc 创建的时候,出现了野指针的现象!-
retain 把语义设置成retain试试
@property(nontatomic , retain)NSString *name;
- (void)setName:(NSString *)name {
if (_name != name)
[_name release];
_name = [name retain];
}
getter方法
-(NSString *)name{
return[[_name retain ]autorelease];
}按照以上方法再来一遍
NSString *name = [[NSString alloc] initWithFormat:@"张三"]; // name引用计数为1 Person *p = [[Person alloc] init]; // p的引用计数为1; [p setName:name]; // 经内部实现, name引用计数为2; p指向name那块空间 [name release]; // name引用计数为 1; NSLog(@"%@", [p name]); NSString *newName = [[NSString alloc] initFormat:@"李四"]; // newName 计数为1; [p setName: newName]; {此时, 经过retain的内部实现, [_name release], 则name计数为0, name自动释放, 接着在执行_name = [name retain]; }; [newName release]; newName计数-1, 所以newName引用计数为1 [p release]; p引用计数为0, 自动释放 此时, newName还没有完全被释放, 所以还有内存问题!!
-
copy 把语义设置成copy
@property(nonatomic, copy)NSString *name;
copy中的setter方法
- (void)setName:(NSString *)name{
if (_name != name){
[_name release];
_name = [name copy];
}
}
getter方法;
- (NSString *)name{
return [[_name retain ] autorelease];
}
引用
NSString *name = [[NSString alloc] initWithFormat:@"张三"]; //name引用计数为1
Person *p = [[Person alloc] init]; // p 引用计数为1;
[p setName: name]; // 拷贝了一份, 拷贝的_name 引用计数为1;p 指向 _name;
[name release] // name 引用计数为0, 自动释放;
NSLog(@"%@", [p name]);NSString *newName = [[NSString alloc] initWithFormat:@"李四"]; // setName引用计数为1; [p setName:newName]; //内部实现 [ _name release] 则name计数为0, 自动释放;_name = [name copy]; 则 copy了一份 newName 计数为1; p指向newName; [newName release]; // newName 计数为0; NSLog(@"%@", [p name]); [p release]; p 引用计数为0, 被释放,
这有存在了与retain一样的问题, _newName没有被释放; 怎么解决?? 在delloc中处理
-
dealloc
dealloc方法, 这个方法在引用计数为0的时候, 由系统自动调用, 使其释放! 因而可以重写delloc方法, 在调用的时候, 把上边有setter方法遗留下来的没有释放的给释放掉!比如 在person.m中重写delloc方法
- (void)dealloc {
[_name release]; // 释放setter方法泄露的实例变量
[super dealloc];
}当 p release之后, 引用计数变为0, 此时会调用dealloc方法, 因为释放了setter方法泄露的实例变量
dealloc的注意事项
注意: 永远不要手动调用dealloc, 在dealloc方法的最后一行必须要写[super dealloc];-
遍历构造器的内存管理
Person.m 中
+(id)personWithName:(NSString *)name{
Person *p = [[Person alloc] initWithName: name]; // 若是用遍历构造器, 这里的alloc 何时释放?
return p;
}
若在 return p; 之前 [p release], retrun 则无返回;
若在 retrun p; 之后[p release], 则也会出现, 无值现象;
最佳方案
+(id)personWithName:(NSString *)name{
Person *p = [[Person alloc] initWithName: name];
return [p autorelease];
}return [p autorelease]是最完美的解决方案, 既不会出现内存泄露, 也不会产生野指针;
内存管理
NSString *houseOfMM = [[NSString alloc] initWithString:'装梵几的三室两厅'];
上面一段代码会执行以下两个动作:
- 在堆上分配一段内存用来存储
@' 装梵几的三室两厅 '
,比如:内存地址为0X1111
内容为' 装梵几的三室两厅'
,- 在栈上分配一段内存用来存储
houseForWife
,比如:地址为0XAAAA
内容自然为0X1111
下面分别看下(assign,retain,copy):
- assign的情况:
NSString * myHouse = [ houseOfMM assign ];
此时myHouse
和houseOfMM
完全相同,地址都是0XAAAA
,内容为0X1111
,即myHouse
只是houseOfMM
的别名,对任何一个操作就等于对另一个操作。因此 retainCount 不需要增加.(同进同出,关系好,一把钥匙,给我拿着)- retain的情况:
NSString * myHouse = [ houseOfMM retain ];
此时myHouse
的地址不再为0XAAAA
,可能为0XAABB
,但是内容依然为0X1111
.因此myHouse
和houseOfMM
都可以管理' 装梵几的三室两厅 '所在的内存。因此 retainCount 需要增加1.(有些独立,各自进出,两把钥匙)
- copy的情况:
NSString * myHouse = [ houseOfMM copy ];
此时会在堆上重新开辟一段内存存放@'装梵几的三室两厅'
,比如0X1122
,内容为@'装梵几的三室两厅',同时会在栈上为myHouse分配空间,比如地址:0XAACC
,内容为0X1122
,因此retainCount增加1供myHouse
来管理0X1122
这段内存.
(两套@'装梵几的三室两厅',条件好,分居了,房子一人一套,所以钥匙一人一把。)
- 什么时候用assign,当然是破房子,简装的房子拉
基础类型(简单类型,原子类型):NSInteger,CGPoint,CGFloat,C数据类型(int,float,double,char等)
- 什么时候用copy
含有可深拷贝的mutable子类的类,如NSArray,NSSet,NSDictionary,NSData的,NSCharacterSet,NSIndexSet,NSString
(可深度拷贝的房子)
但是NSMutableArray这样的不可以,Mutable的不能用copy,不然初始化会有问题。切记
- 什么时候用retain
其他NSObject和其子类对象好嘛 (大多数)
ARC中的strong相当于非ARC中的retain,ARC来了以后多搞一把钥匙就strong了啦。
collection的内存管理
collection 就是NSArray, NSDictionary, NSSet.....等容器类;
collection 会自助管理自己内部的元素;
加入collection中的对象会被retain;
移除出collection的对象会被release;
cellection被释放会对内部所有对象release;-
多态;
多态的特点;
父类指针可以指向不同的子类对象;
允许在多个类中定义同一个消息接口;
可以屏蔽不同子类对象之间的差异, 写出通用代码;
适应需求的不断变化;