昨天在写一个 Model,需要用到 NSCoding 序列化,之前用 Class 是没问题的,但换到Struct 就歇菜了,NSCoding 并不支持 Swift 的结构体。

放狗一搜,找到两种解决方法,这里总结一下:

当 Swift 的结构体遇上 NSCoding

当 Swift 的结构体遇上 NSCoding - 敏捷大拇指 - 当 Swift 的结构体遇上 NSCoding





方法一

为 Struct 增加一个 HelperClass 属性成员(Class),让后让它遵守 NSCoding 协议。接着为结构体添加编码 encode 和解码 decode 的类型方法,这对方法的内部其实是调用了 HelperClass 的 decodeObjectForKey 和 encodeObject 方法。

[Swift] 纯文本查看 复制代码
struct Person {  
  let firstName: String
  let lastName: String
}

extension Person {  
  class HelperClass: NSObject, NSCoding {

    var person: Person?

    init(person: Person) {
      self.person = person
      super.init()
    }

    class func path() -> String {
      let documentsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).first
      let path = documentsPath?.stringByAppendingString("/Person")
      return path!
    }

    required init?(coder aDecoder: NSCoder) {
      guard let firstName = aDecoder.decodeObjectForKey("firstName") as? String else { person = nil; super.init(); return nil }
      guard let laseName = aDecoder.decodeObjectForKey("lastName") as? String else { person = nil; super.init(); return nil }

      person = Person(firstName: firstName, lastName: laseName)

      super.init()
    }

    func encodeWithCoder(aCoder: NSCoder) {
      aCoder.encodeObject(person!.firstName, forKey: "firstName")
      aCoder.encodeObject(person!.lastName, forKey: "lastName")
    }
  }


使用起来也很简单:

[Swift] 纯文本查看 复制代码
let me = Person(firstName: "Dominik", lastName: "Hauser")

Person.encode(me)

let myClone = Person.decode()

firstNameLabel.text = myClone?.firstName  
lastNameLabel.text = myClone?.lastName 





方法二

定义一个 Protocol,包含两个方法:

  • 从结构体中得到一个 NSDictionary 对象
  • 使用一个 NSDictionary 对象初始化结构体


然后 NSDictionary 就可以使用 NSKeyedArchiver 进行序列化。这种方法的优点是:每个遵守该协议的结构体都可以被序列化,下面的代码将结构体归档到 NSUserDefaults 中。

[Swift] 纯文本查看 复制代码
// MARK: -
// MARK: Property list conversion protocol

protocol PropertyListReadable {  
    func propertyListRepresentation() -> NSDictionary
    init?(propertyListRepresentation:NSDictionary?)
}

func extractValuesFromPropertyListArray<T:PropertyListReadable>(propertyListArray:[AnyObject]?) -> [T] {  
    guard let encodedArray = propertyListArray else {return []}
    return encodedArray.map{$0 as? NSDictionary}
        .flatMap{T(propertyListRepresentation:$0)}
}

func saveValuesToDefaults<T:PropertyListReadable>(newValues:[T], key:String) {  
    let encodedValues = newValues.map{$0.propertyListRepresentation()}
    NSUserDefaults.standardUserDefaults()
        .setObject(encodedValues, forKey:key)
}

// MARK: -
// MARK: Coordinates

struct Coordinate {  
    let x:Double
    let y:Double
    let z:Double

    init(_ x: Double, _ y: Double, _ z: Double) {
        self.x = x
        self.y = y
        self.z = z
    }
}

extension Coordinate: PropertyListReadable {  
    func propertyListRepresentation() -> NSDictionary {
        let representation:[String:AnyObject] = ["x":self.x, "y":self.y, "z":self.z]
        return representation
    }

    init?(propertyListRepresentation:NSDictionary?) {
        guard let values = propertyListRepresentation else {return nil}
        if let xCoordinate = values["x"] as? Double,
            yCoordinate = values["y"] as? Double,
            zCoordinate = values["z"] as? Double {
                self.x = xCoordinate
                self.y = yCoordinate
                self.z = zCoordinate
        } else {
            return nil
        }
    }
}





作者:chengway