2017-04-17 119 views
1

工作的時候儘量編碼我的自定義對象的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

回答

1

下面是如何使對象符合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 –

0

這裏是解決方案,您必須實現兩個方法

編碼方法

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