======文档更新状态=====
2015-12-23:发布
==================
day09-[2015-12-22]
一、属性修饰符和方法:copy
1.使用前提:遵循NSCopying协议;并实现copyWithZone:方法
2.作用:克隆出一个与原有对象完全相同(除了存储地址、RC值)的新的对象
3.NSString的特殊性:
A。因为类簇的原因,不同方式(甚至不同OS版本)创建的NSString对象,实际类型不同,对于引用计数、copy等的实现也有其特殊性
B.RC值为-1表示,不需要用户进行内存管理,由系统完成,某些NSString的类簇类需要用户进行RC修改、有些不需要
4.使用copy修饰的属性,一般都需要在dealloc中release,除非是NSString这种特殊的类型
// YYWeapon.h
#import <Foundation/Foundation.h>
@interface YYWeapon : NSObject<NSCopying>
@property (nonatomic,copy)NSString* name;
-(instancetype)initWithName:(NSString*)name;
//+(instancetype)weaponWithName:(NSString*)name;
@end
// YYWeapon.m
#import "YYWeapon.h"
@implementation YYWeapon
// 注意下面copyWithZone的写法
// 注意下面使用id和self的原因(不固定类型,鉴于继承、// 的考虑)
-(id)copyWithZone:(NSZone *)zone{
//在创建新对象时按照已有对象的结构分配内存空间
id tmp=[[self class]allocWithZone:zone];
//将已有对象(self)的属性或成员变量逐一赋值到新对象(tmp)中
[tmp setName:self.name];
//返回新建对象
return tmp;
}
-(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
@property (nonatomic,copy)NSString* name;
@property (nonatomic,copy)YYWeapon* weapon;
-(instancetype)initWithName:(NSString*)name weapon:(YYWeapon*)weapon;
//+(instancetype)heroWithName:(NSString*)name weapon:(YYWeapon*)weapon;
@end
// YYHero.m
#import "YYHero.h"
@implementation YYHero
-(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_copy.m
#import "YYHero.h"
int main_copy(){
YYWeapon* we1=[[YYWeapon alloc]initWithName:@"Yitian"];//1
YYHero* he=[[YYHero alloc]initWithName:@"Zhang" weapon:we1];
YYWeapon* we3=[we1 retain];
NSLog(@"we1:%@,we1:%p",we1,we1);
NSLog(@"we3:%@,we3:%p",we3,we3);
NSLog(@"we1.rc:%lu",we1.retainCount);//2
YYWeapon* we2=[we1 copy];//克隆
NSLog(@"we1:%@,we1:%p",we1,we1);
NSLog(@"we2:%@,we2:%p,we2.rc:%lu",we2,we2,we2.retainCount);
NSLog(@"===========");
we1.name=@"Tulong";
NSLog(@"we1:%@,we2:%@,we3:%@",we1,we2,we3);
//释放
[we3 release];
[we1 release];
[we2 release];
return 0;
}
// test_string.m
// 验证NSString类族的存在
#import <Foundation/Foundation.h>
int main_string(){
NSString* s1=@"hello";
NSString* s2=[NSString stringWithUTF8String:"hello"];
NSString* s3=[NSString stringWithFormat:@"hello"];
NSLog(@"s1:%p,s2:%p,s3:%p",s1,s2,s3);
NSLog(@"s1:%@,s2:%@,s3:%@",[s1 class],[s2 class],[s3 class]);
NSString* s4=[s1 copy];
NSLog(@"s4:%p,s4:%@,s4:%@",s4,[s4 class],s4);
NSString* s5=[s2 copy];
NSLog(@"s5:%p,s5:%@,s5:%@",s5,[s5 class],s5);
NSLog(@"s1.rc:%d;s2.rc:%d",
s1.retainCount,s2.retainCount);
return 0;
}
// test_hero.m
#import "YYHero.h"
int main_hero(){
YYWeapon* we1=[[YYWeapon alloc]initWithName:@"Yitian"];//1
YYHero* he=[[YYHero alloc]initWithName:@"Zhang" weapon:we1];
we1.name=@"tulong";
NSLog(@"he:%@",he);
[he release];
[we1 release];
return 0;
}
注意:
1>copyWithZone的写法
2>除了NSString这种特殊的类外,其他使用copy修饰的属性一般都需要在dealloc中release
二、循环引用
1.概念:在一个类中包含另一个类的对象指针;在另一个类中又包含这个类的对象指针
2.声明语法,不能使用#import,而是使用@class;在各自的实现文件中导入所有的头文件
3.属性修饰符选择上不能都使用retain(死锁,一个都无法销毁),也不能都使用assign(销毁一个会影响另一个);一个使用assign,另一个使用retain(需要注意释放顺序,retain的先释放)
4.尽量避免出现循环引用
// YYHero1.h
#import <Foundation/Foundation.h>
@class YYHorse;
@interface YYHero1 : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,strong)YYHorse* horse;
@end
// YYHero1.m
#import "YYHero1.h"
#import "YYHorse.h"
@implementation YYHero1
-(NSString *)description{
return [NSString stringWithFormat:@"Hero %@ has horse %@.",_name,_horse.name];
}
-(void)dealloc{
NSLog(@"骑着%@马的英雄%@销毁了。",_horse.name,_name);
}
@end
// YYHorse.h
#import <Foundation/Foundation.h>
@class YYHero1;
@interface YYHorse : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,weak)YYHero1* owner;
@end
// YYHorse.m
#import "YYHorse.h"
#import "YYHero1.h"
@implementation YYHorse
-(NSString *)description{
return [NSString stringWithFormat:@"Horse %@'s owner is %@.",_name,_owner.name];
}
-(void)dealloc{
NSLog(@"主人是%@的马%@销毁了.",_owner.name,_name);
// [_owner release];
}
@end
// test_horse1.m
#import "YYHero1.h"
#import "YYHorse.h"
int main_hero1(){
YYHero1* hero=[YYHero1 new];
YYHorse* horse=[YYHorse new];
hero.name=@"Lvbu";
horse.name=@"Chitu";
hero.horse=horse;
horse.owner=hero;
NSLog(@"1.horse:%@",horse);
NSLog(@"1.hero:%@",hero);
// [hero release];
// hero=nil;
// NSLog(@"2.horse:%@",horse);
horse=nil;
NSLog(@"2.hero:%@",hero);
hero=nil;
return 0;
}
三、自动释放池
1.作用:不能立即释放的对象,按照MRC原则又不能在其它地方释放时,使用自动释放池,使其在合适的时候自动释放
2.用法:创建对象时增加autorelease方法的调用,使其具有自动释放标识;在其它地方使用@autoreleasepool{……}块获取对象,在离开arp块时,会自动执行对象的release方法(不保证会执行dealloc);按照规范,在MRC下,创建对象的类方法都应该调用autorelease方法
3.结构:栈式结构,在离开arp时先调用autorelease的对象最后执行release方法;需要注意循环引用对象的创建顺序,retain的后创建
// YYBook.h
#import <Foundation/Foundation.h>
@interface YYBook : NSObject
@property (nonatomic,copy)NSString* title;
@property (nonatomic,assign)int price;
-(instancetype)initWithTitle:(NSString*)title price:(int)price;
+(instancetype)bookWithTitle:(NSString*)title price:(int)price;
@end
// YYBook.m
#import "YYBook.h"
@implementation YYBook
-(instancetype)initWithTitle:(NSString *)title price:(int)price{
if (self=[super init]) {
self.title=title;
self.price=price;
}
return self;
}
+(instancetype)bookWithTitle:(NSString *)title price:(int)price{
return [[[self alloc]initWithTitle:title price:price]autorelease];
}
-(NSString *)description{
return [NSString stringWithFormat:@"Book %@ price is %d.",_title,_price];
}
-(void)dealloc{
NSLog(@"Book %@ dealloc",_title);
[super dealloc];
}
@end
// test_arp1.m
#import "YYBook.h"
/**
* 用于创建YYBook对象的函数
*
* @param title 标题
* @param price 价格
*
* @return YYBook对象指针
*/
YYBook* createBook(NSString* title,int price){
id tmp=[[YYBook new]autorelease];
[tmp setTitle:title];
[tmp setPrice:price];
return tmp;
}
int main_arp1(){
YYBook* bk1=[YYBook new];
bk1.title=@"C语言";
bk1.price=21;
@autoreleasepool {
//不建议在arp外创建的对象,在arp内调用autorelease方法
//[bk1 autorelease];
YYBook* bk=[YYBook bookWithTitle:@"iOS" price:20];
NSLog(@"%@",bk);
YYBook* b2=createBook(@"ObjC", 12);
NSLog(@"%@",b2);
YYBook* b3=[b2 retain];//2
[b3 release];//1
}
NSLog(@"end of main.");
return 0;
}
// test_arp2.m
#import "YYHero1.h"
#import "YYHorse.h"
int main_arp2(){
@autoreleasepool {
// 要注意循环引用对象的创建顺序,retain的后创建
YYHero1* hero=[[YYHero1 new]autorelease];
YYHorse* horse=[[YYHorse new]autorelease];
hero.name=@"Lvbu";
horse.name=@"Chitu";
hero.horse=horse;
horse.owner=hero;
NSLog(@"1.horse:%@",horse);
NSLog(@"1.hero:%@",hero);
}
NSLog(@"end of main");
return 0;
}
四、ARC
1.MRC与ARC的转换:部分,整体
2.属性修饰符的含义:unsafe_unretained
weak 当被引用的对象被释放后会使weak修饰的属性自动变为nil,当再使用它修饰的变量不会报错,固安全
unsafe_unretained不会使其修饰的属性自动变为nil,当再使用它修饰的变量就会报错,固不安全,注意下面
@property (nonatomic,unsafe_unretained)YYSkill* skill;这句话
// YYMonster.h
#import "YYSkill.h"
@interface YYMonster : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,unsafe_unretained)YYSkill* skill;
@end
// YYMonster.m
#import "YYMonster.h"
@implementation YYMonster
-(void)dealloc{
// NSLog(@"Monster %@ with %@ skill dealloc.",_name,_skill.name);
NSLog(@"Monster %@ dealloc.",_name);
}
-(NSString *)description{
return [NSString stringWithFormat:@"Monster %@ with %@ skill.",_name,_skill.name];
}
@end
// YYSkill.h
#import <Foundation/Foundation.h>
@interface YYSkill : NSObject
@property (nonatomic,copy)NSString* name;
@property (nonatomic,assign)int power;
@end
// YYSkill.m
#import "YYSkill.h"
@implementation YYSkill
-(void)dealloc{
NSLog(@"Skill %@ dealloc.",_name);
}
@end
// test_skill.m
#import "YYMonster.h"
int main() {
@autoreleasepool {
YYMonster* mons=[YYMonster new];
YYSkill* sk=[YYSkill new];
sk.name=@"AAAAA";
mons.name=@"WWWW";
mons.skill=sk;
NSLog(@"%@",mons);
}
return 0;
}
运行结果:
2015-12-22 23:54:27.505 1222[1356:55439] Monster WWWW with AAAAA skill.
2015-12-22 23:54:27.506 1222[1356:55439] Skill AAAAA dealloc.
2015-12-22 23:54:27.506 1222[1356:55439] Monster WWWW dealloc.
Program ended with exit code: 0
当把YYMonster.m中的注释打开在僵尸模式下会报错而把
@property (nonatomic,unsafe_unretained)YYSkill* skill;
中的unsafe_unretained改为weak则会输出
2015-12-23 00:02:53.829 1222[1449:58834] Monster WWWW with AAAAA skill.
2015-12-23 00:02:53.831 1222[1449:58834] Skill AAAAA dealloc.
2015-12-23 00:02:53.831 1222[1449:58834] Monster WWWW with (null) skill dealloc.
Program ended with exit code: 0
注意这里的null是由于weak的作用
总之:
weak: 当被引用的对象被释放后会使weak修饰的属性自动变为nil当再使用它修饰的变量不会报错,固安全
unsafe_unretained不会使其修饰的属性自动变为nil,当再使用它修饰的变量会报错。固不安全
===========EOF============