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之间的关系
- foundation可复制的对象,当我们“copy”的是一个“不可变对象”时,他的作用相当于retain(cocoa做的内存优化)
- 当我们使用mutableCopy时,无论源对象是否可变,副本是可变的,并且实现了真正意义上的拷贝
- 当我们copy的是一个可变对象时,副本对象是不可变的,同样实现了真正意义上的copy
自定义对象的归档
- 自定义的对象要支持归档,需要实现NSCoding协议。
- NSCoding协议有两个方法:
- encodeWithCoder方法对对象的属性数据做编码处理。
- 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];
- 自定义内容归档(第二种方式)
归档:
- 使用NSData实例作为归档的存储数据
- 添加归档的内容(设置key与value)(一个key管理一个对象)
- 完成归档
- 将归档数据存入磁盘中
解归档:
- 从磁盘读取数据,生成NSData实例
- 根据Data实例创建和初始化解归档实例
- 解归档,根据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
- 创建单例的基本步骤:
- 声明一个单例对象的静态实例,并初始化为nil
- 创建一个类的类工厂方法,生成一个该类的实例,当且仅当这个类的实例为nil时覆盖allocWithZone:方法,确保用户(程序员)再直接分配和初始化对象时,不会产生另一个对象
- 实现NSCopying协议,覆盖release、autorelease、retain、retainCount方法,以此确保单例的状态。(为了不让它销毁,和修改引用计数)
- 在多线程环境中,注意使用@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 }

浙公网安备 33010602011771号