Проблема Swift NSCoding с одним настраиваемым объектом

Я читал некоторые другие сообщения и не могу понять, почему объект, сохраненный на диск с помощью NSKeyedUnarchiver, всегда выводит пустые строки на консоль. Моя конечная цель — сохранить один пользовательский объект на диск с помощью NSKeyedArchiver.

В настоящее время я изучаю, как использовать Firebase для хранения некоторых данных. У меня есть собственный класс, который представляет пользователя следующим образом:

class User: NSObject, NSCoding {
let key: String
let email: String
let familyKey: String
let username: String
let provider: String
let role: String



// Initialize from arbitrary data
init(key: String, email: String, fKey: String, uName:String, provider:String, role: String) {
    self.key = key
    self.email = email
    self.familyKey = fKey
    self.username = uName
    self.provider = provider
    self.role = role
    super.init()
}

required init?(coder aDecoder: NSCoder) {
    self.key = aDecoder.valueForKey("key") as! String
    self.email = aDecoder.valueForKey("email") as! String
    self.familyKey = aDecoder.valueForKey("familyKey") as! String
    self.username = aDecoder.valueForKey("username") as! String
    self.provider = aDecoder.valueForKey("provider") as! String
    self.role = aDecoder.valueForKey("role") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(self.key, forKey: "key")
    aCoder.encodeObject(self.email, forKey: "email")
    aCoder.encodeObject(self.familyKey, forKey: "familyKey")
    aCoder.encodeObject(self.username, forKey: "username")
    aCoder.encodeObject(self.provider, forKey: "provider")
    aCoder.encodeObject(self.role, forKey: "role")
}

В моем контроллере просмотра регистрации я создаю пользователя и без проблем аутентифицирую пользователя с помощью Firebase. В блоке аутентификации я инициализирую пользовательский объект, используя первый пользовательский инициализатор выше. Я пробовал следующее, чтобы сохранить его, поэтому я считаю, что моя проблема заключается в моем коде выше с кодированием/декодированием данных, поскольку ни один из них не работает.

Локальное архивирование файла по этой ссылке из Взлом со Swift. FBPath.shared.docDir — это просто ссылка NSString на мой каталог документов.

let userPath = FBPath.shared.docDir.stringByAppendingPathComponent("currentUser")
                    let userData = NSKeyedArchiver.archivedDataWithRootObject(newUser)
                    userData.writeToFile(userPath, atomically: true)

Попытка получить это с помощью

let userPath = FBPath.shared.docDir.stringByAppendingPathComponent("currentUser")
    if let user = NSKeyedUnarchiver.unarchiveObjectWithFile(userPath) as? User {
        print(user.username)
    }

Это не сработало, поэтому я попытался сохранить его на диск, используя сообщение Whasssaaahhh здесь post by Whasssaaahhh. Вот код, который действительно работает, но хранит пустой файл.

required convenience init?(coder aDecoder: NSCoder) {

    guard let aKey = aDecoder.decodeObjectForKey("userKey") as? String else {return nil}
    guard let anEmail = aDecoder.decodeObjectForKey("userEmail") as? String else {return nil}
    guard let aFamilyKey = aDecoder.decodeObjectForKey("usersFamilyKey") as? String else {return nil}
    guard let userName = aDecoder.decodeObjectForKey("username") as? String else {return nil}
    guard let aProvider = aDecoder.decodeObjectForKey("userProvider") as? String else {return nil}
    guard let aRole = aDecoder.decodeObjectForKey("userRole") as? String else {return nil}

    self.init(key: aKey, email: anEmail, fKey: aFamilyKey, uName:userName, provider:aProvider, role: aRole)
}

private class func getCurrentUserURL() -> NSURL {
    let documentsDirectory = NSFileManager().URLsForDirectory((.DocumentDirectory), inDomains: .UserDomainMask).first!
    let userPath = documentsDirectory.URLByAppendingPathComponent("currentUser")
    return userPath
}

class func saveCurrentUserToDisk(user:User){
    let success = NSKeyedArchiver.archiveRootObject(user, toFile: User.getCurrentUserURL().path!)
    if !success {
        print("failed to save user to disk")
    }
}
class func loadCurrentUserFromDisk() -> User?{
    return NSKeyedUnarchiver.unarchiveObjectWithFile(User.getCurrentUserURL().path!) as? User
}

В моей регистрации VC для хранения пользователя на диске:

let newUser = User(key: authData.uid, email: self.emailField.text!, fKey: newFamily.key, uName: self.usernameField.text!, provider: authData.provider, role: "parent")
                    newUser.createUserRecords()
                    User.saveCurrentUserToDisk(newUser)

Затем, чтобы попытаться получить доступ к данным:

if let user = User.loadCurrentUserFromDisk() {
        print(user)
    }

См. редактирование ниже Печатает пустую строку. Я в недоумении, что делать, чтобы сохранить этого пользователя на диск. Основываясь на этой попытке, кажется, что не стоит пытаться сохранить это в пользовательских настройках по умолчанию, и это такой небольшой набор данных, как у одного пользователя, что в любом случае не повредит сохранить объект данных на диске. Просто нужно выяснить, почему я не могу заставить это работать. Я также попытался обновить все переменные экземпляра с let на var и назначить «» в качестве строковых значений. Я надеюсь, что вторая пара глаз поможет мне увидеть, что мне здесь не хватает. Заранее спасибо!

РЕДАКТИРОВАТЬ: когда я изменил переменные экземпляра на vars и установил их значение в пустую строку, теперь объект не возвращается, и ничего не выводится на консоль. Если я верну их обратно, пользователь выведет на консоль пустую строку, хотя я не перезаписал описание. Если я попытаюсь напечатать переменные экземпляра, он снова напечатает пустую строку.

Поэтому я также решил проверить местоположение. Ценности все есть. Просто не восстанавливает их с помощью NSKeyedUnarchiver. Я напечатал местоположение файла, чтобы убедиться, что он пытается получить доступ к правильному местоположению, и все в порядке. XML документа здесь не очень хорошо отображается. Я новичок на сайте, не могу загрузить файл. Но я просмотрел сгенерированный plist, и все там. Я не далек от того, чтобы отказаться от этого и просто вручную сохранять данные в plist. Не уверен, какие проблемы могут возникнуть по сравнению с преимуществами NSKeyedArchiver и использования NSCoding.


person matthew    schedule 12.02.2016    source источник
comment
Вы говорите, что print(user) печатает пустую строку, но если вы не переопределили description, вы ожидаете, что он напечатает имя класса, а не пустую строку.   -  person Michael    schedule 12.02.2016
comment
Точно, поскольку я не перезаписывал описание, я использовал его только для проверки правильности возврата объекта. Это также немного изменилось, так как я установил переменные экземпляра в var, а объект не извлекался. Обновлю мой вопрос, чтобы показать это.   -  person matthew    schedule 12.02.2016
comment
Стоит отметить, что если какой-либо из охранников не работает в удобном инициализаторе, вы выходите из инициализации. Возможно, лучше использовать такой шаблон, как let aKey = aDecoder.decodeObjectForKey("userKey") as? String ?? "".   -  person Michael    schedule 13.02.2016
comment
Это сработало. Оказывается, проблема с семейным ключом. Семейный ключ сохраняется в сгенерированном plist.... и теперь о той части, которая заставляет меня чувствовать себя ужасно. Я забыл, что обновил ключи, чтобы они не конфликтовали с ключами объекта Family (и я никогда не обновлял эту ветку). Я добавил к ним пользователя, за исключением того, что при кодировании семейного ключа он правильный как userFamilyKey, но при декодировании я устанавливаю ключ как usersFamilyKey. Один лишний символ сломал его. Не могу поверить, что я никогда не замечал, что когда я увидел объект, он был сохранен! Большое спасибо за совет :-)   -  person matthew    schedule 13.02.2016


Ответы (1)


Проблема заключалась в том, что охранные статусы останавливали инициализацию разархивируемого объекта. Я перешел от защитных операторов к операторам let, присваивающим пустую строку, если она не может декодировать значение, как предложил Майкл в комментариях выше. Это помогло мне найти значение с неправильным ключом, чтобы я мог обновить код. Теперь все хорошо.

person matthew    schedule 15.02.2016