iOS 深浅拷贝

-(void)copyDemo
{
//    在非集合类对象中:对immutable对象进行copy操作,是指针复制,mutableCopy操作时内容复制;对mutable对象进行copy和mutableCopy都是内容复制。用代码简单表示如下:
//    
//    [immutableObject copy] // 浅复制
//    [immutableObject mutableCopy] //深复制
//    [mutableObject copy] //深复制
//    [mutableObject mutableCopy] //深复制
    
//    在集合类对象中,对immutable对象进行copy,是指针复制,mutableCopy是内容复制;对mutable对象进行copy和mutableCopy都是内容复制。但是:集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。用代码简单表示如下:
//    
//    [immutableObject copy] // 浅复制
//    [immutableObject mutableCopy] //单层深复制
//    [mutableObject copy] //单层深复制
//    [mutableObject mutableCopy] //单层深复制
    
//    Baby *baby = [[Baby alloc] init]; //必须实现copy方法
//    baby.babyName = @"wei";
    
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithCapacity:10];
    [dic setObject:@"1" forKey:@"key1"];
    NSMutableArray *array1 = [[NSMutableArray alloc] initWithObjects:dic,dic, nil];
    NSMutableArray *array2 = [array1 mutableCopy];//单层深拷贝
    NSMutableArray *array3 = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES];//里面dic变成不可变了
    NSMutableArray* array4 = [NSKeyedUnarchiver unarchiveObjectWithData:
                                  [NSKeyedArchiver archivedDataWithRootObject: array1]];//里面dic改变不影响其他数组(其与方法都会影响其他数组)
    [array2 removeObjectAtIndex:0];
    [[array4 objectAtIndex:0] setObject:@"3" forKey:@"key1"];
//    [[array4 objectAtIndex:1] setBabyName:@"8888"];
    
    DLog(@"%@ 
 %@ 
 %@ 
 %@",array1,array2,array3,array4);
}

下面是文章补充 

从面向对象到Objective-C概览copy

面向对象:

In object-oriented programming, object copying is creating a copy of an existing object, a unit of data in object-oriented programming. The resulting object is called an object copy or simply copy of the original object. Copying is basic but has subtleties and can have significant overhead. There are several ways to copy an object, most commonly by a copy constructor or cloning. Copying is done mostly so the copy can be modified or moved, or the current value preserved. If either of these is unneeded, a reference to the original data is sufficient and more efficient, as no copying occurs.

在面向对象的程序设计中,对象的copy就是创建一个已经存在的对象的copy。这种对象的创建的结果被称为原始对象的copy。copy是很基础的,但是也有其精巧的地方,并且可能造成巨大的消耗。有很多种方式可以copy对象,最常用的就是copy构造器和克隆。copy经常用于对象的修改、移动和保护。如果上述的几种应用都不需要,持有原始对象的引用就足够了,并不需要copy。

OC:

In Objective-C, the methods copy and mutableCopy are inherited by all objects and intended for performing copies; the latter is for creating a mutable type of the original object. These methods in turn call the copyWithZone and mutableCopyWithZone methods, respectively, to perform the copying. An object must implement the corresponding copyWithZone method to be copyable.

在OC中,copy和mutableCopy两个方法是被所有对象继承的(有点小毛病,应该指所有继承自NSObject的类),这两个方法就是为copy准备的。其中,mutableCopy是为了创建原始对象的可变类型的copy。这两个方法分别调用copyWithZone和mutableCopyWithZone两个方法来进行copy。一个对象必须实现copyWithZone或者mutableCopyWithZone,才能进行copy或者mutableCopy。

那么,我们可以从以上获取到什么信息?

  • copy经常用于对象的修改、移动和保护。如果上述的几种应用都不需要,持有原始对象的引用就足够了,并不需要copy。

  • 一个类必须实现copyWithZone或者mutableCopyWithZone,才能进行copy或者mutableCopy。

下一阶段,本文将展开讲述OC中的copy相关信息以及如何使用copy方法。

Objective-C中copy相关 

1、OC中的copy相关内容

  • 在XCode 里Foundation.framework下的Headers里,也在系统里找到原文件:/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSObject.h

@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end

  • 在/usr/include/objc 下面找到 runtime 的 NSObject.h

- (id)copy;
- (id)mutableCopy;

  • 修饰属性的关键字copy

2、这里需要注意的有以下几点

  • 若想使用copy和mutableCopy,需要分别实现NSCopying协议和NSMutableCopying协议,即实现copyWithZone:和mutableCopyWithZone:方法。

  • 继承自NSObject的大部分框架类均默认实现了NSCopying,并且一些具备可变类型的类如NSString、NSArray、NSDictionary,以及它们的可变类型类NSMutableString、NSMutableArray和NSMutableDictionary也实现了NSMutableCopying。(查了大部分常用类,均实现了NSCopying,所以暂时这么说吧,可能有人说NSNumber并没有实现NSCopying,那你可以看一下它的父类NSValue,其实现了NSCopying)

  • 对于一些自定义类,需要自己实现NSCopying。具体方式且看下部分。

非容器对象的深浅copy

首先,我们谈一下非容器对象的深浅copy,这些非容器对象,包含常用的NSString、NSNumber等,也包括我们自定义的一些非容器类的实例。下面分三个三面进行分析。

1、首先说说深浅copy

准则

浅copy: 指针复制,不会创建一个新的对象。

深copy: 内容复制,会创建一个新的对象。

此处,不进行过多的解释,从下面的结果分析中,按例子来理解。

2、框架类的深浅copy

准则

探究框架类深copy还是浅copy,需要清楚的是该类如何实现的NSCopying和NSMutableCopy的两个方法copyWithZone:和mutableCopyWithZone:。然而OC并不开源,并且本文这里也不会进行源码的推测。

那么,我们应该遵循怎样一个原则呢?如下:

  • 对immutableObject,即不可变对象,执行copy,会得到不可变对象,并且是浅copy。

  • 对immutableObject,即不可变对象,执行mutableCopy,会得到可变对象,并且是深copy。

  • 对mutableObject,即可变对象,执行copy,会得到不可变对象,并且是深copy。

  • 对mutableObject,即可变对象,执行mutableCopy,会得到可变对象,并且是深copy。

代码

// 此处以NSString为例探究框架类深浅copy


// 不可变对象NSString *str = @"1";
NSString *str1 = [str copy];
NSString *str2 = [str mutableCopy];

// 可变对象NSMutableString *mutableStr = [NSMutableString stringWithString:@"1"];
NSMutableString *mutableStr1 = [mutableStr copy];
NSMutableString *mutableStr2 = [mutableStr mutableCopy];

// 打印对象的指针来确认是否创建了一个新的对象

// 不可变对象原始指针

NSLog(@"%p", str);
// 不可变对象copy后指针NSLog(@"%p", str1);
// 不可变对象mutalbeCopy后指针NSLog(@"%p", str2);

// 可变对象原始指针NSLog(@"%p", mutableStr);
// 可变对象copy后指针NSLog(@"%p", mutableStr1);
// 可变对象mutalbeCopy后指针NSLog(@"%p", mutableStr2);

结果分析

// 此处依次对应上述6个log,可见与前面所讲的原则吻合(此处不验证可变类型和不可变类型,默认上述原则正确即可)。

2016-10-21 10:50:52.879 Memory[67680:5623387] 0x10d85a1b0

2016-10-21 10:50:52.879 Memory[67680:5623387] 0x10d85a1b0

2016-10-21 10:50:52.879 Memory[67680:5623387] 0x60800007a080

2016-10-21 10:50:52.879 Memory[67680:5623387] 0x60800007a9c0

2016-10-21 10:50:52.880 Memory[67680:5623387] 0xa000000000000311

2016-10-21 10:50:52.880 Memory[67680:5623387] 0x60800007a900

3、自定义类的深浅copy

准则

对于一个我们自定义的类型,显然比框架类容易操纵的多。此处就拿NSCopying举例(因为从没有自定义过具有可变类型的类,当然,如果有需要的话,也可以实现NSMutableCopying)。自定义的类就和2中的原则没有半毛钱关系了,一切就看你怎么实现NSCopying协议中的copyWithZone:方法。

代码

// Model定义,copyWithZone第一种实现(浅copy)

@interface Model1 : NSObject <NSCopying>

@property (nonatomic, assign)  NSInteger a;

@end

@implementation Model1
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
@end

// Model定义,copyWithZone第二种实现(深copy)

@interface Model1 : NSObject <NSCopying>

@property (nonatomic, assign) NSInteger a;
@end

@implementation Model1
- (id)copyWithZone:(NSZone *)zone {
    Model1 *model = [[Model1 allocWithZone:zone] init];
    model.a = self.a;
    return model;
}
@end

// 分别选择上述两种model进行指针打印。
Model1 *model = [[Model1 alloc] init];
Model1 *copyModel = [model copy];

NSLog(@"%p", model);
NSLog(@"%p", copyModel);

结果分析

// 对应上述一,可见实现了浅copy
2016-10-21 11:12:03.149 Memory[67723:5636292] 0x60000000c9d0
2016-10-21 11:12:03.149 Memory[67723:5636292] 0x60000000c9d0
// 对应上述二,可见实现了深copy
2016-10-21 11:16:46.803 Memory[67752:5640133] 0x60800001df00
2016-10-21 11:16:46.803 Memory[67752:5640133] 0x60800001def0

容器对象的深浅copy 

前文已经知道了深浅copy的区别,你也大致猜到了为什么将容器对象拿出来作为一块。对,因为容器中可能包含很多对象,而这些对象也需要区分深浅copy。往深里说,容器中可能包含容器对象,那更是麻烦了。不要急,看下面,以NSArray的深浅copy为例,将容器的深浅copy分为四种。

1、浅copy

准则

容器的浅copy,符合三.2中的原则。

代码

// 和NSString浅copy的验证步骤一样

NSArray *arr = [NSArray arrayWithObjects:@"1", nil];
NSArray *copyArr = [arr copy];

NSLog(@"%p", arr);
NSLog(@"%p", copyArr);

// 结果分析

// 无疑是浅copy(你可能会问,为什么不看一下arr和copyArr内部元素的指针对比?这里并没有必要,最外层对象都没有创建新的,里面不用验证)

2016-10-21 11:27:57.554 Memory[67778:5646253] 0x600000010690

2016-10-21 11:27:57.554 Memory[67778:5646253] 0x600000010690

2、单层深copy

准则

容器的单层深copy,符合三.2中的原则(只是深copy变成了单层深copy)。这里的单层指的是完成了NSArray对象的深copy,而未对其容器内对象进行处理。

代码

NSArray *arr = [NSArray arrayWithObjects:@"1", nil];
NSArray *copyArr = [arr mutableCopy];

NSLog(@"%p", arr);
NSLog(@"%p", copyArr);

// 打印arr、copyArr内部元素进行对比NSLog(@"%p", arr[0]);
NSLog(@"%p", copyArr[0]);

结果分析

// 可发现前两项地址不同,即完成深copy,但是后两项相同,这代表容器内部的元素并没有完成深copy,所有称之为单层深copy

2016-10-21 11:32:27.157 Memory[67801:5649757] 0x6000000030d0

2016-10-21 11:32:27.157 Memory[67801:5649757] 0x600000242e50

2016-10-21 11:32:27.157 Memory[67801:5649757] 0x10dd811b0

2016-10-21 11:32:27.157 Memory[67801:5649757] 0x10dd811b0

3、双层深copy

准则

容器的双层深copy已经脱离了三.2中的原则。这里的双层指的是完成了NSArray对象和NSArray容器内对象的深copy(为什么不说完全,是因为无法处理NSArray中还有一个NSArray这种情况)。

代码

// 随意创建一个NSMutableString对象

NSMutableString *mutableString = [NSMutableString stringWithString:@"1"];


// 随意创建一个包涵NSMutableString的NSMutableArray对象

NSMutableString *mutalbeString1 = [NSMutableString stringWithString:@"1"];
NSMutableArray *mutableArr = [NSMutableArray arrayWithObjects:mutalbeString1, nil];


// 将mutableString和mutableArr放入一个新的NSArray中

NSArray *testArr = [NSArray arrayWithObjects:mutableString, mutableArr, nil];
// 通过官方文档提供的方式创建

copyNSArray *testArrCopy = [[NSArray alloc] initWithArray:testArr copyItems:YES];

// testArr和testArrCopy指针对比

NSLog(@"%p", testArr);
NSLog(@"%p", testArrCopy);

// testArr和testArrCopy中元素指针对比

// mutableString对比

NSLog(@"%p", testArr[0]);
NSLog(@"%p", testArrCopy[0]);
// mutableArr对比NSLog(@"%p", testArr[1]);
NSLog(@"%p", testArrCopy[1]);

// mutableArr中的元素对比,即mutalbeString1对比

NSLog(@"%p", testArr[1][0]);
NSLog(@"%p", testArrCopy[1][0]);

结果分析

// 这里可以发现,copy后,只有mutableArr中的mutalbeString1指针地址没有变化。而testArr的指针和testArr中的mutableArr、mutableString的指针地址均发生变化。所以称之为双层深复制。
2016-10-21 12:03:15.549 Memory[67855:5668888] 0x60800003c7a0
2016-10-21 12:03:15.549 Memory[67855:5668888] 0x60800003c880
2016-10-21 12:03:15.549 Memory[67855:5668888] 0x608000260540
2016-10-21 12:03:15.550 Memory[67855:5668888] 0xa000000000000311
2016-10-21 12:03:15.550 Memory[67855:5668888] 0x60800005d610
2016-10-21 12:03:15.550 Memory[67855:5668888] 0x60800000d2e0
2016-10-21 12:03:15.550 Memory[67855:5668888] 0x608000260980
2016-10-21 12:03:15.550 Memory[67855:5668888] 0x608000260980

限制

initWithArray: copyItems:会使NSArray中元素均执行copy方法。这也是我在testArr中放入NSMutableArray和NSMutableString的原因。如果我放入的是NSArray或者NSString,执行copy后,只会发生指针复制;如果我放入的是未实现NSCopying协议的对象,调用这个方法甚至会crash。这里,官方文档的描述有误。

If the objects in the collection have adopted the NSCopying

protocol, the objects are deeply copied to the new collection, which is then the sole owner of the copied objects.

4、完全深copy

准则

如果想完美的解决NSArray嵌套NSArray这种情形,可以使用归档、解档的方式。

代码

// 随意创建一个NSMutableString对象

NSMutableString *mutableString = [NSMutableString stringWithString:@"1"];
// 随意创建一个包涵NSMutableString的NSMutableArray对象

NSMutableString *mutalbeString1 = [NSMutableString stringWithString:@"1"];
NSMutableArray *mutableArr = [NSMutableArray arrayWithObjects:mutalbeString1, nil];
// 将mutableString和mutableArr放入一个新的NSArray中

NSArray *testArr = [NSArray arrayWithObjects:mutableString, mutableArr, nil];
// 通过归档、解档方式创建

copyNSArray *testArrCopy = [NSKeyedUnarchiver unarchiveObjectWithData:

                            [NSKeyedArchiver archivedDataWithRootObject:testArr]];;

// testArr和testArrCopy指针对比

NSLog(@"%p", testArr);
NSLog(@"%p", testArrCopy);

// testArr和testArrCopy中元素指针对比

// mutableString对比

NSLog(@"%p", testArr[0]);
NSLog(@"%p", testArrCopy[0]);


// mutableArr对比

NSLog(@"%p", testArr[1]);
NSLog(@"%p", testArrCopy[1]);

// mutableArr中的元素对比,即mutalbeString1对比

NSLog(@"%p", testArr[1][0]);
NSLog(@"%p", testArrCopy[1][0]);

结果分析

// 可见完成了完全深复制,testArr和testArrCopy中的元素,以及容器中容器的指针地址完全不同,所以完成了完全深复制。

2016-10-21 12:19:34.022 Memory[67887:5677318] 0x60800002db00

2016-10-21 12:19:34.022 Memory[67887:5677318] 0x60800002dc20

2016-10-21 12:19:34.022 Memory[67887:5677318] 0x608000260400

2016-10-21 12:19:34.023 Memory[67887:5677318] 0x6080002603c02016-10-21 12:19:34.023 Memory[67887:5677318] 0x608000051d90

2016-10-21 12:19:34.023 Memory[67887:5677318] 0x6080000521e0

2016-10-21 12:19:34.023 Memory[67887:5677318] 0x608000260600

2016-10-21 12:19:34.023 Memory[67887:5677318] 0x6080002606c0

限制

归档和解档的前提是NSArray中所有的对象都实现了NSCoding协议。

拾遗 

1、关键字copy

代码与结果

// 首先分别给出copy和strong修饰的属性,以NSString举例

// 1、strong
@property (nonatomic, strong) NSString *str;
// 2、copy
@property (nonatomic, copy) NSString *str;

// 分别对1和2执行下述代码
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"123"];
self.str = mutableStr;
[mutableStr appendString:@"456"];
NSLog(@"%@", self.str);
NSLog(@"%p", self.str);
NSLog(@"%@", mutableStr);
NSLog(@"%p", mutableStr);

// 结果12016-10-21 14:08:46.657 Memory[68242:5714288] 123456

2016-10-21 14:08:46.657 Memory[68242:5714288] 0x608000071040

2016-10-21 14:08:46.657 Memory[68242:5714288] 123456

2016-10-21 14:08:46.657 Memory[68242:5714288] 0x608000071040

// 结果22016-10-21 14:11:16.879 Memory[68264:5716282] 123

2016-10-21 14:11:16.880 Memory[68264:5716282] 0xa000000003332313

2016-10-21 14:11:16.880 Memory[68264:5716282] 123456

2016-10-21 14:11:16.880 Memory[68264:5716282] 0x60000007bbc0

分析

  • 结果1为strong修饰的结果,可见 [mutableStr appendString:@"456"]修改mutableStr造成了self.str的改变,显然不安全;结果2为copy修饰的结果,可见 [mutableStr appendString:@"456"]修改mutableStr未造成self.str的改变,显然安全。(从内存地址的变化也可以看出来)

  • 这里可以推测出,copy关键字是在str属性的set方法里面返回了mutableStr的copy,而strong关键字仅仅是返回了mutableStr。

2、深浅copy对引用计数的影响

浅copy,类似strong,持有原始对象的指针,会使retainCount加一。

深copy,会创建一个新的对象,不会对原始对象的retainCount变化。

// 也许你会疑问arc下如何访问retainCount属性,这里提供了两种方式(下面代码中a代表一个任意对象,这个对象最好不要是NSString和NSNumber,因为用它们进行测试会出问题)

// kvc方式

NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)a));
// 桥接字方式

NSLog(@"Retain count %@", [a valueForKey:@"retainCount"]);

3、可变和不可变

可变和不可变上文谈的不是很多,因为本文认为这完全与NSCopying和NSMutableCopying的实现息息相关。当然,对于框架类,我们可以简单的认为,copy方法返回的就是不可变对象,mutableCopy返回的就是可变对象。如果是自定义的类,就看你怎么实现NSCopying和NSMutableCopying协议了。

4、copy和block

首先,MRR时代用retain修饰block会产生崩溃,因为作为属性的block在初始化时是被存放在静态区的,如果block内调用外部变量,那么block无法保留其内存,在初始化的作用域内使用并不会有什么影响,但一旦出了block的初始化作用域,就会引起崩溃。所有MRC中使用copy修饰,将block拷贝到堆上。

其次,在ARC时代,因为ARC自动完成了对block的copy,所以修饰block用copy和strong都无所谓。

5、strong和shallowCopy

这个问题困惑了很久,最后只能得出一个结论,浅copy和strong引用的区别仅仅是浅copy多执行一步copyWithZone:方法

外篇:

NSCoding/NSKeyedArchiver

在构建应用程序时,一个重要的架构决策问题是在每次启动之间如何持久化数据。问题是如何精准的重现最后一次关闭应用前的状态;如何描述对象图以使下次完美地重新构建。

 
在 iOS 和 Mac OS X 上, 苹果提供了两种选择 :Core Data 或 NSKeyedArchiver / NSKeyedUnarchiver (用来将遵循 <NSCoding> 的类序列化)
 
或者更确切地说:有三种选择,如果你算上NSURLCache的话. 在client-server应用场景下,在每次启动时加载必要的数据是一种可行的设计,尤其是结合磁盘缓存,存储服务器的响应,这样当发送对应请求的时候可以立即返回。在实践中,网络层和对象层上的缓存结合是可取的。
 
当涉及到建模,查询,遍历,持久化复杂的对象图,那Core Data是无可代替的。Core Data 是把大锤子,但不是所有的问题都是足够大的钉子。
 
Core Data 和 NSKeyedArchiver客观和常见的比较可能是这样的:
 
等等。在这场对决中,没有什么可比性,它看起来是一边倒的局势。
 
……也就是说,直到你从一个稍微不同的角度看它:
 
通过这些对比,在某些情况下NSKeyedArchiver是一个完全合理的选择。并非所有的应用程序需要查询的数据。并非所有的应用程序需要自动迁移。并非所有的应用程序处理大型或复杂的对象图。而且应用中确实是有一些模块更好地被一个简单的方案解决。
 
这篇文章将关注如何,何时,为什么选择NSKeyedArchiver 和 NSCoding。希望能提供给亲爱的读者们以启发选择最合适的工具。
 
NSCoding 是一个简单的协议,有两个方法: -initWithCoder: 和 encodeWithCoder:。遵循NSCoding协议的类可以被序列化和反序列化,这样可以归档到磁盘上或分发到网络上。
 
举个例子:
@interface Book : NSObject <NSCoding> 
@property NSString *title; 
@property NSString *author; 
@property NSUInteger pageCount; 
@property NSSet *categories; 
@property (getter = isAvailable) BOOL available; 
@end 
 
@implementation Book 
 
#pragma mark - NSCoding 
 
- (id)initWithCoder:(NSCoder *)decoder { 
    self = [super init]; 
    if (!self) { 
        return nil; 
    } 
 
    self.title = [decoder decodeObjectForKey:@"title"]; 
    self.author = [decoder decodeObjectForKey:@"author"]; 
    self.pageCount = [decoder decodeIntegerForKey:@"pageCount"]; 
    self.categories = [decoder decodeObjectForKey:@"categories"]; 
    self.available = [decoder decodeBoolForKey:@"available"]; 
 
    return self; 
} 
 
- (void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:self.title forKey:@"title"]; 
    [encoder encodeObject:self.author forKey:@"author"]; 
    [encoder encodeInteger:self.pageCount forKey:@"pageCount"]; 
    [encoder encodeObject:self.categories forKey:@"categories"]; 
    [encoder encodeBool:[self isAvailable] forKey:@"available"]; 
} 
 
@end 
 
如上,NSCoding 主要是样板文件。每个属性用属性名作为key,编码或解码成一个对象或者类型。(有些开发者喜欢定义NSString *常量用作keypath, 其实通常这是没必要的)
 
但是在控制整个序列化过程中样板文件有时候也是非常有用的东西,它可以保持灵活,可以这样解释:
 
Migrations: 如果一个数据模型发生变化,如添加,重命名或删除一个字段,这应该与之前序列化的数据保持兼容性。Apple提供了一些参考"Forward and Backward Compatibility for Keyed Archives".
 
Archiving non-NSCoding-compatible Classes: 根据面向对象设计原则,对象应该可以被编码和解码成一种序列化的格式。但是如果一个类不是内置遵循NSCoding,你可以后续让这个类遵循NSCoding来达到目的。
 
Mantle是一个意在减少写NSCoding样板文件的类库。如果你正在寻找更方便使用NSCoding代替Core Data创建model的方法,那Mantle值得一看。
 
当然,序列化只是故事的一部分。决定把数据持久化到什么地方又是另一个问题。同样,这里有两个方法:写入本地文件系统或者使用NSUserDefaults。
 
File System
NSKeyedArchiver 和 NSKeyedUnarchiver 提供了很方便的API把对象读取/写入磁盘。
 
一个基于NSCoding的table view controller可以通过file manager设置它的属性集合。
 
Archiving
[NSKeyedArchiver archiveRootObject:books toFile:@"/path/to/archive"]; 

 

Unarchiving
[NSKeyedUnarchiver unarchiveObjectWithFile:@"/path/to/archive"]; 

 

NSUserDefaults
 
每个应用程序都有自己的user preferences,它可以存储和检索遵循NSCoding协议的对象或者是C类型数据。
 
然而不推荐将整个对象图存入NSUserDefaults,但是用这种方式编码复合对象是不错的选择,例如“当前用户”的对象或者API credentials(用 Keychain 来代替)。
 
Archiving
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:books]; 
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"books"]; 
 
Unarchiving
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"books"]; 
NSArray *books = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
 
作为开发者,我们是有义务去理解我们应用程序的目标和需求,并且抑制住过于工程化和过早优化的冲动。
 
在应用程序中使用Core Data的决定或许是显而易见的。但是在很多情况下,Core Data 被发现是如此的笨拙或者不必要的,甚至是一种对可用性的障碍,更不用说实用性。
 
即使很多应用在某些方面_可能_受益于Core Data,让事物从简单演化到复杂是必要的,其中蕴含着智慧。但是就持久化而言,它不会比NSCoding更简单。
原文地址:https://www.cnblogs.com/weiboyuan/p/5070512.html