OC学习_9_内存管理_MRC_ARC

======文档更新状态=====
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============

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值