OC语言_06复制对象与归档

  • 复制对象的基本概念
  • 深/浅拷贝的概念异同
  • 拷贝自定义对象
  • retain和copy之间的区别
  • 对象归档的概念和用法
  • 单例设计模式

复制对象的基本概念:

      • 复制一个对象作为副本,它会开辟一块新的内存(堆内存)来存储副本对象,就像复制文件一样。即原文件和副本对象是两块不同的内存区域。
      • 对象具备复制功能,必须实现<NSCopying>协议、<NSMutableCopying>协议
      • 常用的可复制对象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableString、NSMutableArray、NSMutableDictionary 
  • 复制对象的种类
    • copy:产生对 象的副本是不可变的
    • mutableCopy:产生的对象副本是可变的
1     NSArray *arr0 = [NSArray arrayWithObject:@"23"];
2     NSArray *arr1 = [arr0 copy];
3     NSLog(@"%p", arr0);
4     NSLog(@"%p", arr1);//内存地址相同
5     NSMutableArray *arr2 = [NSMutableArray arrayWithObject:@"23"];
6     NSMutableArray *arr3 = [arr2 copy];
7     NSLog(@"%p", arr2);
8     NSLog(@"%p", arr3);//内存地址不同    

 


深、浅拷贝的概念异同

      • 浅复制:只复制对象的本身,对象里的属性、包含的对象不做复制。(属性相同,相当于retain)
      • 深复制:复制对象的本身、对象里的属性也会复制一份(属性内存不同)
      • Foundation框架中支持复制的类,默认是浅复制。
  • 对象的自定拷贝

 

对象拥有复制特性,须实现NSCopying、NSMutableCopying协议。

实现该协议的copyWithZone:方法和mutableCopyWithZone:方法。

实现协议的方法,就可以实现拷贝的功能

1 (id)copyWithZone:(NSZone *)zone {
2     User *user = [[self class] allocWithZone:zone] init];
3     user.data = _data;
4     return user; } 

 

1 (id)mutableCopyWithZone:(NSZone *)zone {

2     UserMutable *user = [[self class] allocWithZone:zone] init];

3     user.data = _data;

4     return user;5 }

 

  • 深浅复制的区别就在于对copyWithZone的不同实现
浅复制的实现
  • 1 (id)copyWithZone:(NSZone *)zone {
    2     User *user = [[self class] allocWithZone:zone] init];
    3     user.name = _name;
    4     user.age = _age;
    5     user.data = _data;
    6     return user;}

     

深复制的实现

1 -(id)copyWithZone:(NSZone *)zone
2       User *user = [[self class] allocWithZone:zone] init];
3       user.name = [_name copy];
4       user.age = [_age copy];
5       user.data = [_data copy];
6       return user; }

 

  • copy retain和mutableCopy之间的关系
    1. foundation可复制的对象,当我们“copy”的是一个“不可变对象”时,他的作用相当于retain(cocoa做的内存优化)
    2. 当我们使用mutableCopy时,无论源对象是否可变,副本是可变的,并且实现了真正意义上的拷贝
    3. 当我们copy的是一个可变对象时,副本对象是不可变的,同样实现了真正意义上的copy

 


自定义对象的归档

      • 自定义的对象要支持归档,需要实现NSCoding协议。
      • NSCoding协议有两个方法:
        1. encodeWithCoder方法对对象的属性数据做编码处理。
        2. initWithCoder解码归档数据来初始化对象
      • 实现NSCoding协议后,就能通过NSKeyedArchiver归档
      • 对name、age、等属性,最好定义宏 #define AGE @“age”


//编码方法,对属性编码,归档的时候会调用

1 -(void)encodeWithCoder:(NSCoder *)aCoder {
2     [aCoder encodeObject:_name forKey:@“name”];
3     [aCoder encoderObject:_apples forKey:@“apples”];
4     [aCoder encoderObject:_age forKey:@“age”];} 


//解码方法 对属性解码,解归档调用

1 -(void)encodeWithCoder:(NSCoder *)aCoder {
2     [aCoder encodeObject:_name forKey:@“name”];
3     [aCoder encoderObject:_apples forKey:@“apples”];
4     [aCoder encoderObject:_age forKey:@“age”];} 


实例:

//归档
User *user = [[[User alloc] init] autorelease];
user.name = @“jack”;
user.age = 12;
NSString *path = [NSHomeDirectory () stringByAppendingPathComponent:@“xxx.text”];
[NSKeyedArchiver archiverRootObject:user toFile:path];

//解归档
NSString *path = [NSHomeDirectory () stringByAppendingPathComponent:@“xxx.text”];
User *user = [NSKeyedArchiver unArchiver unarchiverObjectWithFile:path];
(NSString *)description { return [NSString stringWithFormat:@“age = %d, name = %@”, _age, _name];
}

 


 对象归档的基本概念和用法

      • 概念:对象归档是指将对象写入文件保存在硬盘上,当再次重新打开程序时,可以还原这些对象。

 

(对象序列化,对象持久化)

      • 数据持久性的方式:

 

-NSKeyedArchiver--对象归档

-NSUserDefaults

-属性列表化(NSArray、NSDictionary保存文件)

-SQlite数据库、Core Data数据库(数据量比较大的情况)


      • 归档的形式:

 

对Foundation库中对象进行归档

自定义对象进行归档(需要实现归档协议,NSCoding)

归档后的文件是加密的,属性列表是明文的(只能保存Foundation里几个自带的对象NSArray、NSDictionary等。

 

将一个数组序列化和反序列化(缺陷:一个对象对应一个归档文件)

 

 1 //NSKeyedArchiver 
 2 NSString *homeDirectory = NSHomeDirectory();
 3 NSArray *array = @[@123, @456, @“999”, @“ooo”];
 4 NSString *path = [homeDirectory stringByAppendingPathComponent:@“array.archive”];
 5 //扩展名可以随便取,告诉操作系统以什么文件打开,里面的内容不变
 6 if ([NSKeyedArchiver archiverRootObject:array toFile:path]) {
 7     NSLog(@“archiver success”);
 8 }
 9 
10 
11 //解归档
12 NSArray *unArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 


      • 自定义内容归档(第二种方式)

归档:

        1. 使用NSData实例作为归档的存储数据
        2. 添加归档的内容(设置key与value)(一个key管理一个对象)
        3. 完成归档
        4. 将归档数据存入磁盘中

 

解归档:

        1. 从磁盘读取数据,生成NSData实例
        2. 根据Data实例创建和初始化解归档实例
        3. 解归档,根据key访问value的值

 

 1 实例:自定义一个基本数据类型和一个Objective-C对象类型,进行对象的归档和解归档
 2 //归档(序列化)
 3 NSString *homePath = NSHomeDirectory();
 4 NSString *filePath = [homePath stringByAppendingPathComponent:@“customContent.archive”];
 5 //将数据放入,必须是可变data
 6 NSMutableData *data = [NSMutableData data];
 7 //创建归档对象
 8 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
 9 NSArray *array = @[“Jack”, “Tom”];
10 //添加归档对象encode
11 [archiver encodeInt:100 forKey:@“age”];
12 [archiver encodeObject:array forKey:@“name”];
13 [archiver finishEncoding];
14 [archiver release];
15 //监听是否写入成功
16 BOOL success = [data  writeToFile:path atomically:YES];
17 if(success) {NSLog(@“success”);}
19 //解归档(反序列化)
20 NSString *homePath = NSHomeDirectory();
21 NSString *filePath = [homePath stringByAppendingPathComponent:@“customContent.archive”];
22 NSData *data = [NSData dataWithContentsFile:path];
23 NSKeyedUnarchiver *unArchiver = [NSKeyedArchiver alloc] initForReadingWithMutableData:data];
24 int age = [unArchiver decodeIntForKey:@”age”];
25 [unArchiver release];
26 NSArray *names = [unArchiver decodeObjectForKey:@“name”];
27 }  

单例设计模式(和代理模式同属于设计模式)

      • 设计原理:始终返回一个实例,即一个类始终只有一个实例,只初始化一次。
      • 意图:   1.这个单例对象作为全局对象       2.避免重量级对象的重复创建
      • Foundation用过的对象单例有:NSFileManager
        • 创建单例的基本步骤:

        1. 声明一个单例对象的静态实例,并初始化为nil
        2. 创建一个类的类工厂方法,生成一个该类的实例,当且仅当这个类的实例为nil时覆盖allocWithZone:方法,确保用户(程序员)再直接分配和初始化对象时,不会产生另一个对象
        3. 实现NSCopying协议,覆盖release、autorelease、retain、retainCount方法,以此确保单例的状态。(为了不让它销毁,和修改引用计数)
        4. 在多线程环境中,注意使用@synchronized关键字,确保静态实例被正确的创建和初始化。

 

 1 //单例的基本实现
 2 //定义静态对象和工厂方法
 3 static File *shareFile = nil;
 4 +(File *)shareFile{
 5 @synchronized(self) {
 6  //加同步锁,线程保护
 7 if (shareFile == nil)
 8 {
 9     shareFile = [[self alloc] init];
10         }
11     }
12     return shareFile;
13 }
14 
15 //覆盖allocWithZone:方法
16 +(id)allocWithZone:(NSZone *)zone{
17     NSLog(@“ nil  %p”, zone);
18     @synchronized(self){
19     if(shareFile ==nil){
20     shareFile = [super allocWithZone:zone];
21     return shareFile;
22         }
23     }
24     return shareFile;
25 }
26 
27 //实现copy协议,覆盖与内存相关的方法
28 -(id)copyWithZone:(NSZone *)zone{
29     return self;
30 }//实现copy协议,返回本身
31 
32 -(id)retain{ 
33     return self;
34 }//返回本身
35 
36 -(NSUInteger)retainCount{
37     return UINT_MAX;
38 }//返回一个无符号整型范围最大值
39 
40 -(oneway void)release{}//什么都不做
41 
42 -(id)autorelease{return self;}//返回对象本身

 

NSUserDefaults

存储的文件后缀是.plist

//用于存放小数据

1 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
2     NSArray *array = nil;
3     [ud setInteger:123 forKey:@"number"];
4     [ud setObject:array forKey:@"array"];
5     [ud synchronize];
6     NSInteger number = [ud integerForKey:@"number"];
7     NSLog(@"%ld", number);
8 }

今日习题

小明有一个地址薄(内容:姓名、性别、年龄、住址)这个地址薄可以实现增加、删除的功能

 1 重写方法
 2 //归档
 3 //编码方法
 4 - (void)encodeWithCoder:(NSCoder *)aCoder
 5 {
 6     [aCoder encodeObject:_name forKey:@"name"];
 7     [aCoder encodeObject:_sex forKey:@"sex"];
 8     [aCoder encodeObject:_age forKey:@"age"];
 9     [aCoder encodeObject:_adrr forKey:@"adrr"];
10 }
11 
12 //解码方法
13 - (id)initWithCoder:(NSCoder *)aDecoder
14 {
15     self = [super init];
16     if (self != nil) {
17         self.name = [aDecoder decodeObjectForKey:@"name"];
18         self.sex = [aDecoder decodeObjectForKey:@"sex"];
19         self.age = [aDecoder decodeObjectForKey:@"age"];
20         self.adrr = [aDecoder decodeObjectForKey:@"adrr"];
21     }
22     return self;
23 }
24 
25 NSString *homePath = NSHomeDirectory();
26 NSString *path = [homePath stringByAppendingPathComponent:@"axxx.archive"];
27 NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
28 [NSKeyedArchiver archiveRootObject:array toFile:path]
29 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


posted @ 2015-04-04 19:25  captivity  阅读(146)  评论(0)    收藏  举报