NSKeyedArchiver.archivedData 不适用于 Swift 3 iOS

NSKeyedArchiver.archivedData does not work in Swift 3 iOS

当尝试在 iOS 中编码我的自定义对象时 swift 从 Xcode 8.3

得到这个错误

unrecognized selector sent to instance 0x60800166fe80 *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.

我的代码是这样的:

导入 UIKit 进口基金会

class Place: NSObject {

    func setCustomObject(CustomObject obj:Any,Key key:String) {

        let encodedObject : Data = NSKeyedArchiver.archivedData(withRootObject: obj)
        UserDefaults.standard.set(encodedObject, forKey: key)

    }
}

这是一个如何使对象符合 NSCoding 的示例。基本上你需要提供两种方法的实现 - required convenience init?(coder decoder: NSCoder)encode(with aCoder: NSCoder)

class Book: NSObject, NSCoding {
  var title: String?
  var pageCount: Int?

  // Memberwise initializer
  init(title: String,pageCount: Int) {
   self.title = title
   self.pageCount = pageCount
  }

  // MARK: NSCoding


  // Here you will try to initialize an object from archve using keys you did set in `encode` method.
  required convenience init?(coder decoder: NSCoder) {
    guard let title = decoder.decodeObject(forKey: "title") as? String else { return nil }

    self.init(title: title, pageCount: decoder.decodeInteger(forKey: "pageCount"))
  }

  // Here you need to set properties to specific keys in archive
  func encode(with aCoder: NSCoder) {
    aCoder.encode(self.title, forKey: "title")
    aCoder.encodeCInt(Int32(self.pageCount), forKey: "pageCount")
  }
}

此外,我建议将您的 setCustomObject 方法更改为:

func setCustomObject(obj:NSCoding, key:String) {
  let encodedObject : Data = NSKeyedArchiver.archivedData(withRootObject: obj)
  UserDefaults.standard.set(encodedObject, forKey: key)
}

这样编译器会阻止您传递 NSKeyedArchiver 不符合 NSCoding 协议的对象。

如果您不想在 init 方法中提供所有属性,您可以使用默认值:

init(title : String? = nil, pageCount: Int? = nil){
  self.title = title
  self.pageCount = pageCount
}

现在您可以在没有任何属性的情况下初始化您的对象。就那样Book()

这里是解决方案,你必须实现这两个方法

编码方法

func encode(with aCoder: NSCoder)

解码方式

 required init?(coder aDecoder: NSCoder)

完整的示例代码

class User: NSObject , NSCoding
{


var userID : Int = 0
var name : String = ""
var firstName : String = ""
var lastName : String = ""
var username : String = ""
var email : String = ""

override init(){
    super.init();
}

func encode(with aCoder: NSCoder) {

    aCoder.encode(self.userID,  forKey: "id");
    aCoder.encode(self.firstName,    forKey: "first_name");
    aCoder.encode(self.lastName,    forKey: "last_name");
    aCoder.encode(self.name,    forKey: "name");
    aCoder.encode(self.username,forKey: "username");
    aCoder.encode(self.email,   forKey: "email");
}

required init?(coder aDecoder: NSCoder) {
    super.init()

    self.userID     = aDecoder.decodeInteger(forKey: "id");
    self.firstName  = aDecoder.decodeObject(forKey: "first_name") as! String;
    self.lastName   = aDecoder.decodeObject(forKey: "last_name") as! String;
    self.name       = aDecoder.decodeObject(forKey: "name") as! String
    self.username   = aDecoder.decodeObject(forKey: "username") as! String
    self.email      = aDecoder.decodeObject(forKey: "email") as! String;
}

init(data : [String: AnyObject]) {

    super.init()

    self.userID = String.numberValue(data["user_id"]).intValue;
    self.firstName = String.stringValue(data["first_name"]);
    self.lastName = String.stringValue(data["last_name"]);
    self.email = String.stringValue(data["email"]);
    self.username = String.stringValue(data["user_name"]);
}

class func loadLoggedInUser()  -> User {

    if let  archivedObject = UserDefaults.standard.object(forKey:"CurrentUserAcc"){

        if let user  = NSKeyedUnarchiver.unarchiveObject(with: (archivedObject as! NSData) as Data) as? User {

            return user;
        }

    }

    return User()
}

func saveUser(){

    let archivedObject : NSData = NSKeyedArchiver.archivedData(withRootObject: self) as NSData

    UserDefaults.standard.set(archivedObject, forKey: "CurrentUserAcc");

    UserDefaults.standard.synchronize();
}

func deleteUser(){

    UserDefaults.standard.set(nil, forKey: "CurrentUserAcc")

    UserDefaults.standard.synchronize();
} 
}