NSCoding自定义对象子数组不会持久化

时间:2016-04-06 17:43:11

标签: ios swift

我有两个班:联系人和比尔。联系人有一个类型为Bill的数组。

当我坚持使用NSKeyedArchiver时,我的联系人仍然存在,但是,它不会保留Bill数组。

每次我添加一个比尔或联系人时,我都会坚持使用insertNewObject()方法。

以下是我的课程:

/* Persist.swift */
import Foundation

class Persist {

    static let sharedInstance = Persist()

    let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
    var contactsFilePath : String {
        let manager = NSFileManager.defaultManager()
        let url = manager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as NSURL
        return url.URLByAppendingPathComponent("\(delegate.userId):objectsArrayz").path!
    }

    func insertNewObject(){
        NSKeyedArchiver.archiveRootObject(delegate.contacts!, toFile: contactsFilePath)

    }

    func retrieveContracts(){
        if let array = NSKeyedUnarchiver.unarchiveObjectWithFile(contactsFilePath) as? [Contact] {
            delegate.contacts = array
        }
    }

    func deleteContact(rowNum : Int){
        delegate.contacts!.removeAtIndex(rowNum)
        NSKeyedArchiver.archiveRootObject(delegate.contacts!, toFile: contactsFilePath)
    }

/* Contact.swift */    
import Foundation

class Contact : NSObject, NSCoding{

    var image : UIImage?
    var firstName : String?
    var lastName : String?
    var email : String?
    var phoneNumber : String?
    var address : String?
    var bills : [Bill]?

    init(image: UIImage, firstName : String, lastName : String, email : String, phoneNumber : String, address : String, bills : [Bill]) {
        self.image = image
        self.firstName = firstName
        self.lastName = lastName
        self.email = email
        self.phoneNumber = phoneNumber
        self.address = address
        self.bills = bills
    }

    // MARK: NSCoding

    required convenience init?(coder decoder: NSCoder) {
        guard let image = decoder.decodeObjectForKey("image") as? UIImage,
            let firstName = decoder.decodeObjectForKey("firstName") as? String,
            let lastName = decoder.decodeObjectForKey("lastName") as? String,
            let email = decoder.decodeObjectForKey("email") as? String,
            let phoneNumber = decoder.decodeObjectForKey("phoneNumber") as? String,
            let address = decoder.decodeObjectForKey("address") as? String,
            let bills = decoder.decodeObjectForKey("bills") as? [Bill]
        else {
                return nil
        }

        self.init(
            image: image,
            firstName: firstName,
            lastName : lastName,
            email : email,
            phoneNumber : phoneNumber,
            address : address,
            bills : bills

        )
    }

    func encodeWithCoder(coder: NSCoder) {
        coder.encodeObject(self.image, forKey: "image")
        coder.encodeObject(self.firstName, forKey: "firstName")
        coder.encodeObject(self.lastName, forKey: "lastName")
        coder.encodeObject(self.email, forKey: "email")
        coder.encodeObject(self.phoneNumber, forKey: "phoneNumber")
        coder.encodeObject(self.address, forKey: "address")
        coder.encodeObject(self.bills, forKey: "bills")
    }
}


/* Bill.swift*/
import Foundation

class Bill : NSObject, NSCoding{

    var service : String?
    var subtotal : Double?
    var taxes : Double?
    var total : Double?


    init(service : String, subtotal : Double, taxes : Double, total: Double) {
        self.service = service
        self.subtotal = subtotal
        self.taxes = taxes

    }

    // MARK: NSCoding

    required convenience init?(coder decoder: NSCoder) {

        guard let service = decoder.decodeObjectForKey("service") as? String,
            let subtotal = decoder.decodeObjectForKey("subtotal") as? Double,
            let taxes = decoder.decodeObjectForKey("taxes") as? Double,
            let total = decoder.decodeObjectForKey("total") as? Double

            else {
                return nil
        }


        self.init(
            service: service,
            subtotal: subtotal,
            taxes: taxes,
            total: total

        )
    }

    func encodeWithCoder(coder: NSCoder) {
        coder.encodeObject(self.service, forKey: "service")
        coder.encodeObject(self.subtotal, forKey: "subtotal")
        coder.encodeObject(self.taxes, forKey: "taxes")
        coder.encodeObject(self.total, forKey: "total")
    }
}

2 个答案:

答案 0 :(得分:1)

以下是apple dev docs的指南(在objective-c中):

  

讨论你必须从initWithCoder返回self:如果你有   先进的需要,需要替换后的另一个对象   解码,你可以在awakeAfterUsingCoder中这样做:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html

- (void)encodeWithCoder:(NSCoder *)coder {
    [super encodeWithCoder:coder];
    // Implementation continues
}

- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        _firstName = [coder decodeObjectForKey:ASCPersonFirstName];
        _lastName = [coder decodeObjectForKey:ASCPersonLastName];
        _height = [coder decodeFloatForKey:ASCPersonHeight];
    }
    return self;
}

答案 1 :(得分:0)

可序列化类的init方法需要调用super.init()。

来自Bill.swift的片段

 required init?(coder decoder: NSCoder) {
        super.init()
        service = decoder.decodeObjectForKey("service") as? String
        subtotal = decoder.decodeObjectForKey("subtotal") as? Double
        taxes = decoder.decodeObjectForKey("taxes") as? Double
        total = decoder.decodeObjectForKey("total") as? Double
        services = decoder.decodeObjectForKey("services") as? [Service]
    }