所谓对象归档,其实就是类似于其他语言中的序列化机制,归档通常就是用某种格式把一个或者多个对象保存到指定的文件中,方便以后从文件中恢复它们.通常来说,归档包含两方面的操作:一方面需要把对象写入指定的文件,另一方面需要从文件中恢复这些对象.这是一种常用的数据化持久存储的方式。如下图讲多个对象进行归档操作:
使用NSKeyedArchiver归档
与NSKeyedArchiver相对应的还有一个NSKeyedUnarchiver类,其中NSKeyedArchiver负责就爱那个对象归档到指定的文件中,而NSKeyedUnarchiver则负责从文件中恢复这些对象.NSKeyedArchiver会创建一种所谓的带键(keyed)的档案,在这种归档格式中,无论归档哪个对象,程序都需要为该对象分配一个key(即所谓的键),当程序希望从文件中恢复这些对象时,也需要根据key进行检索.
NSKeyedArchiver与NSKeyedUnarchiver的用法有如下:
1)直接调用NSKeyedArchiver的+ (NSData *)archivedDataWithRootObject:(id)rootObject;
+ (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;类方法将指定的对象作为root进行归档,存储到指定的路径下;
2)获取规定对象时,则调用NSKeyedUnarchiver的+ (nullable id)unarchiveObjectWithData:(NSData *)data;
+ (nullable id)unarchiveObjectWithFile:(NSString *)path;方法.
直接使用如下:
归档自定义对象
1)如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
2)但不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以,所以要归档自定义对象,那么要遵守NSCoding协议并实现有2个方法:encodeWithCoder:每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量 initWithCoder:每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量.
例子如下:
自定义类的实现:
使用归档实现深复制
想详细了解归档方面的内容,可以看官方文档。
使用Swift实现自定义归档
定义一个Book类,遵守NSCoding协议,实现协议方法
class Book: NSObject, NSCoding {
var title: String
var author: String
var pageCount: Int
init(title: String, author: String, pageCount: Int) {
self.title = title
self.author = author
self.pageCount = pageCount
}
// MARK: NSCoding
required convenience init?(coder aDecoder: NSCoder) {
guard let title = aDecoder.decodeObject(forKey: "title") as? String,
let author = aDecoder.decodeObject(forKey: "author") as? String else { return nil }
let pageCount = aDecoder.decodeInteger(forKey: "pageCount")
self.init(title: title, author: author, pageCount: pageCount)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(title, forKey: "title")
aCoder.encode(author, forKey: "author")
aCoder.encode(pageCount, forKey: "pageCount")
}
}
使用归档
let document = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = document.appending("/book.archive")
let book = Book(title: "iOS developer", author: "Apple", pageCount: 500)
if NSKeyedArchiver.archiveRootObject(book, toFile: filePath) {
print("archive book success")
} else {
print("archive book failure")
}
if let data = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Book {
print("book: \(data.title)")
}
配合UserDefaults存储多个对象
func archiveBooks() {
var books: [Book] = []
for _ in 0..<10 {
let book = Book(title: "iOS developer", author: "Apple", pageCount: 500)
books.append(book)
}
let defaults = UserDefaults.standard
let data = NSKeyedArchiver.archivedData(withRootObject: books)
defaults.set(data, forKey: "books")
defaults.synchronize()
if let data = defaults.object(forKey: "books") as? Data,
let books = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Book] {
print(books)
}
}
参考