NSKeyedArchiver.archivedData不斯威夫特3的iOS

问题描述:

工作的时候尽量编码我的自定义对象的iOS迅速在Xcode 8.3NSKeyedArchiver.archivedData不斯威夫特3的iOS

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) 

    } 
} 
+0

做你的'CustomObject'符合'NSCoding'协议吗? – njuri

+0

否@njuri,是否需要? –

+1

是的,将在答案中描述。 – njuri

下面是如何使对象符合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()

+0

我有这个例子的主要问题,我的对象有太多的属性,现在,如果每次我想实例新对象必须初始化对象与所有属性是不nesesarry:| @njuri –

+0

我希望我的新对象实例包含零属性@njuri –

+0

已经在Objective C中使用RMMAper,它非常容易使用,但新增功能非常复杂且不可用@njuri –

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

编码方法

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(); 
} 
}