在Swift实现Struct归档

struct AboutMe {
    var detail: String
    var links: [[String : String]]
}

在Swift中,Struct类型是无法进行归档操作的,只有继承自NSObject并且遵守了NSCoding协议的类才可以进行相应的归档操作。也就是将上面结构体改成类:

class AboutMe: NSObject, NSCoding {
    var detail: String
    var links: [[String : String]]
    required init?(coder aDecoder: NSCoder) {
        aDecoder.decodeObjectForKey("detail")
        aDecoder.decodeObjectForKey("links")
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(detail)
        aCoder.encodeObject(links)
    }
}

但是如果要对Struct进行归档,可以转换思维,使用按照以下步骤实现。

实现一个归档、解档协议:
public protocol Archivable {
    func archive() -> NSDictionary
    init?(unarchive: NSDictionary?)
}

因为NSKeyedArchiver可以直接对Foundation类进行操作,所以可以将结构体中的属性都转换成字典,然后进行后续操作;archive函数返回一个归档好的字典,而可失败构造函数传入一个需要解档的字典。

让AboutMe遵守并实现以上声明的协议
extension AboutMe: Archivable{
    func archive() -> NSDictionary {
        return ["detail" : detail, "links" : links]
    }
    
    init?(unarchive: NSDictionary?) {
        guard let values = unarchive else { return nil }
        if let detail = values["detail"] as? String,
            links = values["links"] as? [[String : String]] {
                self.detail = detail
                self.links = links
        } else {
            return nil
        }
    }
}

这里使用扩展进行归解档方法的添加,可以看到,原先结构体的属性在接口上都是以字典的形势在传输。

实现归解档函数
public func unarchiveObjectWithFile<T: Archivable>(path: String) -> T? {
    return T(unarchive: NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? NSDictionary)
}

public func archiveObject<T: Archivable>(object: T, toFile path: String) {
    NSKeyedArchiver.archiveRootObject(object.archive(), toFile: path)
}

对AboutMe进行字典化后,NSKeyedArchiver可以直接对其进行操作,所以这个实现并不复杂。

完成以上步骤,就可以对Struct进行归档和接档操作了:

let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).first! + "/AboutMe"
let aboutMe = AboutMe(detail: "tripleCC", links: [["github" : "https://github.com/tripleCC"], ["gitblog" : "http://triplecc.github.io/"]])
archiveObject(aboutMe, toFile: path)
let unAboutMe: AboutMe? = unarchiveObjectWithFile(path)
debugPrint(unAboutMe)

如果要进行集合操作,可以添加以下函数:

public func archiveObjectLists<T: Archivable>(lists: [T], toFile path: String) {
    let encodedLists = lists.map{ $0.archive() }
    NSKeyedArchiver.archiveRootObject(encodedLists, toFile: path)
}

public func unarchiveObjectListsWithFile<T: Archivable>(path: String) -> [T]? {
    guard let decodedLists = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [NSDictionary] else { return nil }
    return decodedLists.flatMap{ T(unarchive: $0) }
}

参考博客

1.NSCoding And Swift Structs

2.Property Lists And User Defaults in Swift

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,232评论 4 61
  • 1、 沙盒概念基本介绍 iOS 应用程序只能在该 app 的文件系统中读取。这个默认的 app 文件系统就是我们说...
    Laughingg阅读 2,768评论 2 10
  • 作者:何少波 一生一世的情人/安静的拉在手里/凝视着远方/看着它绽放/
    南塬牛阅读 261评论 0 1
  • (一) 你步伐稳健行走匆匆, 我平静如水温柔相随, 我们的目的地是远方。 (二) 浩瀚星辰中, 皎洁月光下, 你说...
    H二多阅读 566评论 0 4
  • 大柴旦下公路沿主路走不了多远能看到人民宾馆,炕锅羊肉的店就在宾馆招牌下,叫回香阁,肉价肉量实惠,65/斤,里面有炕...
    月舞戎沙阅读 407评论 0 0