======文档更新状态=====
2015-12-21:发布
==================
day08-[2015-12-21]
一、MRC(手动引用计数、手动内存管理)
1.内存管理机制:每个对象都有一个引用计数器retainCount,用来记录堆空间中的对象在栈中有多少指针指向,一旦没有指针指向该空间,则释放
2.Xcode6默认使用ARC,设置automatic reference counting为NO开启MRC
3.过程:
A。新建对象时,retainCount(以下简称RC)被置为1;
B。调用retain方法,RC加1;
C。调用release方法,RC减1;当RC为1时调用release方法,则不再减1,而是直接调用对象的dealloc方法进行释放
4.原则:
A。谁创建谁release
B。谁retain谁release
C。release后立即置为nil,否则在开启“Zombie”模式时会报错
D。不要手动调用dealloc
5.dealloc重写要求:在MRC下,最后一定要有[super dealloc];将父类部分的释放交给父类去做
// YYPerson.h
#import <Foundation/Foundation.h>
@interface YYPerson : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,assign)int age;
@end
// YYPerson.m
#import "YYPerson.h"
@implementation YYPerson
-(void)dealloc{
NSLog(@"Person %@ dealloc.",_name);
[super dealloc];
}
@end
// main.m
#import "YYPerson.h"
int main_person(int argc, const char * argv[]) {
YYPerson* p1=[YYPerson new];
p1.name=@"mike";
NSLog(@"p1.rc:%lu",p1.retainCount);//1
YYPerson* p2=[p1 retain];
NSLog(@"p2.rc:%lu,p1.rc:%lu",p2.retainCount,p1.retainCount);//2,2
YYPerson* p3=[p2 retain];
NSLog(@"p2.rc:%lu,p3.rc:%lu",p2.retainCount,p3.retainCount);//3,3
[p3 release];
p3=nil;
NSLog(@"p2.rc:%lu,p3.rc:%lu",p2.retainCount,p3.retainCount);//2,2
[p2 release];
p2=nil;
NSLog(@"1.p2.rc:%lu,p1.rc:%lu",p2.retainCount,p1.retainCount);//1,1
[p1 release];
p1=nil;
NSLog(@"2.p2.rc:%lu,p1.rc:%lu",p2.retainCount,p1.retainCount);//1,1
return 0;
}
二、MRC下的对象嵌套
1.对象嵌套:在一个类中包含另一个类的对象指针,例如:代理模式中主类Manager的代理delegate(id<代理协议>类型)、圆形Circle里的圆心cener(Point类型)
2.MRC下的内存分析:command+shift+B
如果有提示(关键词leak),则很有可能发生内存泄露(不是绝对的);如果没有提示,则可能性较小(也是有泄露可能的)
3.对象嵌套的内存问题(以Hero和Weapon为例)
A.嵌套对象变成僵尸或无法释放,解决:在给嵌套对象指针赋值时使用retain方法,在释放包含嵌套对象的dealloc方法中release
B.改变嵌套对象指针指向的地址(如Hero更换Weapon),解决:改写setter,判断当前指针是否与新指针相同,如果相同什么都不做;如果不同,先将当前指针release,再通过retain获取新指针
// YYWeapon.h
#import <Foundation/Foundation.h>
@interface YYWeapon : NSObject
{
@private
NSString* _name;
}
-(void)setName:(NSString*)name;
-(NSString*)name;
-(instancetype)initWithName:(NSString*)name;
//+(instancetype)weaponWithName:(NSString*)name;
@end
// YYWeapon.m
#import "YYWeapon.h"
@implementation YYWeapon
-(void)setName:(NSString *)name{
_name=[name copy];
}
-(NSString *)name{
return _name;
}
-(instancetype)initWithName:(NSString *)name{
if (self=[super init]) {
self.name=name;
}
return self;
}
//+(instancetype)weaponWithName:(NSString *)name{
// return [[self alloc]initWithName:name];
//}
-(void)dealloc{
NSLog(@"Weapon %@ dealloc.",_name);
[super dealloc];
}
-(NSString *)description{
return [NSString stringWithFormat:@"Weapon(%@)",_name];
}
@end
// YYHero.h
#import "YYWeapon.h"
@interface YYHero : NSObject
{
@private
NSString* _name;
YYWeapon* _weapon;
}
-(void)setName:(NSString*)name;
-(NSString*)name;
-(void)setWeapon:(YYWeapon*)weapon;
-(YYWeapon*)weapon;
-(instancetype)initWithName:(NSString*)name weapon:(YYWeapon*)weapon;
//+(instancetype)heroWithName:(NSString*)name weapon:(YYWeapon*)weapon;
@end
// YYHero.m
#import "YYHero.h"
@implementation YYHero
-(void)setName:(NSString *)name{
_name=[name copy];
}
-(NSString *)name{
return _name;
}
-(void)setWeapon:(YYWeapon *)weapon{
if (_weapon!=weapon) {
[_weapon release];
_weapon=[weapon retain];
}
}
-(YYWeapon *)weapon{
return _weapon;
}
-(instancetype)initWithName:(NSString *)name weapon:(YYWeapon *)weapon{
if (self=[super init]) {
self.name=name;
self.weapon=weapon;
}
return self;
}
//+(instancetype)heroWithName:(NSString *)name weapon:(YYWeapon *)weapon{
// return [[self alloc]initWithName:name weapon:weapon];
//}
-(void)dealloc{
NSLog(@"Hero %@ with %@ dealloc.",_name,_weapon.name);
[_weapon release];
[super dealloc];
}
-(NSString *)description{
return [NSString stringWithFormat:@"Hero %@ using %@",_name,_weapon];
}
@end
// test_hero1.m
#import "YYHero.h"
int main_hero1(){
// YYWeapon* sword=[YYWeapon weaponWithName:@"Yitian"];
// YYHero* zhang=[YYHero heroWithName:@"Zhang" weapon:sword];
YYWeapon* sword=[[YYWeapon alloc]initWithName:@"Yitian"];
YYHero* zhang=[[YYHero alloc ]initWithName:@"Zhang" weapon:sword];
NSLog(@"%@",zhang);
[sword release];
NSLog(@"%@",zhang);
[zhang release];
return 0;
}
// test_hero2.m
#import "YYHero.h"
int main_hero2(){
YYWeapon* sword=[[YYWeapon alloc]initWithName:@"Yitian"];
YYWeapon* knife=[[YYWeapon alloc]initWithName:@"Tulong"];
YYHero* zhang=[[YYHero alloc ]initWithName:@"Zhang" weapon:sword];
NSLog(@"%@",zhang);
zhang.weapon=sword;
NSLog(@"After change weapon:%@",zhang);
[sword release];
[knife release];
[zhang release];
return 0;
}
三、和MRC相关的属性修饰符
1.assign
A。基本类型一定使用assign
B。对象指针使用时表示不修改引用计数
2.retain
A。仅用于OC对象指针或id类型
B。在赋值时,自动调用retain方法;如果已经指向旧的对象指针,则会先调用旧指针的release
C。必须在dealloc中调用该属性的release方法
// YYSkill.h
#import <Foundation/Foundation.h>
@interface YYSkill : NSObject
@property (nonatomic,copy)NSString* name;
@end
// YYSkill.m
#import "YYSkill.h"
@implementation YYSkill
-(NSString *)description{
return [NSString stringWithFormat:@"%@",_name];
}
-(void)dealloc{
NSLog(@"Skill %@ dealloc.",_name);
[super dealloc];
}
@end
// YYMonster.h
#import "YYSkill.h"
@interface YYMonster : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,retain)YYSkill* skill;
@end
// YYMonster.m
#import "YYMonster.h"
@implementation YYMonster
-(NSString *)description{
return [NSString stringWithFormat:@"Monster %@ has %@ skill.",_name,_skill.name];
}
-(void)dealloc{
[_skill release];
NSLog(@"Monster %@ dealloc.",_name);
[super dealloc];
}
@end
// test_monster.m
#import "YYMonster.h"
int main(){
YYSkill* sk=[YYSkill new];
sk.name=@"打狗棒";
YYSkill* sk2=[YYSkill new];
sk2.name=@"十八掌";
YYMonster* mons=[YYMonster new];
mons.name=@"洪七";
mons.skill=sk;//2
NSLog(@"mons:%@",mons);
mons.skill=sk2;
NSLog(@"mons:%@",mons);
[sk release];
[sk2 release];
[mons release];
return 0;
}
==========EOF================