天天看点

iOS数据持久化---NSCoding

1.数据模型:在传统的类定义基础上,加上(1)数据存储地址ArchiveURL(2)继承NSObject,遵从NSCoding协议(实现用于将数据编码的func encode(with aCoder: NSCoder),实现将归档数据恢复为类数据对象的required convenience init?(coder aDecoder: NSCoder)。) 只用遵从NSCoding协议的类才能被编码归档。

import UIKit

import os.log

class Country:NSObject,NSCoding {

    //MARK:Property

    let name:String

    var nationalFlagImage:UIImage

    var capital:String

    var mainCities:[String]

    //MARK:创建数据存储的url路径

    //(1)使用FileManager对象,获得用户域的通用目录的url

    static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!

    //(2)创建用于存储的url路径:在DocumentsDirectory基础上,加上路径元素,相当于在DocumentsDirectory路径下,创建了一个文件 夹,用于存放数据

    static let ArchiveURL = DocumentsDirectory.appendingPathComponent("countries")

    init(name:String,nationalFlagImage:UIImage,capital:String,mainCities:[String]) {

        self.name = name

        self.nationalFlagImage = nationalFlagImage

        self.capital = capital

        self.mainCities = mainCities

        //这句话时初始化父类NSObject

        super.init()

    }

    ///持久化相关代码

    //(1)为Country类中的所有属性设置相应的键名,类似于数据里面的属性名

    struct PropertyKey {

        static let name = "name"

        static let nationalFlagImage = "nationalFlagImage"

        static let capital = "capital"

        static let mainCities = "mainCities"

    }

    //(2)让Country类继承 NSObject 类,并实现 NSCoding 协议

    // 继承了 NSObject 类,需要在本类初始化时,完成父类的初始化

    // NSCoding协议需要实现 encode 函数和 init?初始化函数

    // 为每个属性绑定相应的键名,以键名编码

    func encode(with aCoder: NSCoder){

        aCoder.encode(name, forKey: PropertyKey.name)

        aCoder.encode(nationalFlagImage, forKey: PropertyKey.nationalFlagImage)

        aCoder.encode(capital, forKey: PropertyKey.capital)

        aCoder.encode(mainCities, forKey: PropertyKey.mainCities)

    }

    // 以键名解码

    required convenience init?(coder aDecoder: NSCoder){

        guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {

            os_log("无法完成解码", log: .default, type: .debug)

            return nil

        }

        guard let nationalFlagImage = aDecoder.decodeObject(forKey: PropertyKey.nationalFlagImage) as? UIImage else {

            os_log("无法完成解码", log: .default, type: .debug)

            return nil

        }

        guard let capital = aDecoder.decodeObject(forKey: PropertyKey.capital) as? String else {

            os_log("无法完成解码", log: .default, type: .debug)

            return nil

        }

        guard let mainCities = aDecoder.decodeObject(forKey: PropertyKey.mainCities) as? [String] else {

            os_log("无法完成解码", log: .default, type: .debug)

            return nil

        }

        self.init(name: name, nationalFlagImage: nationalFlagImage, capital: capital, mainCities: mainCities)

    }

}

2. 使用 NSKeyedArchiver.archiveRootObject(countries, toFile: Country.ArchiveURL.path)实现Country数组数据的归档存储。

使用 NSKeyedUnarchiver.unarchiveObject(withFile: Country.ArchiveURL.path) as? [Country]实现已归档数据的重新载入,解码。