Обновление кодируемой пользовательской структуры - PullRequest
0 голосов
/ 21 января 2020

Я разрабатываю приложение, в котором пользователь может создать до 5 профилей, когда я столкнулся с проблемой.

Проблема:

Неустранимая ошибка : Неожиданно обнаружен ноль при развертывании необязательного значения: файл

Информация:

В первом издании приложения есть структура со следующими точками данных:

  • id
  • profileName
  • profileIcon

Когда приложение открывается, оно загружает пользователя через func loadUser()

Теперь, во время обновления я добавил новую точку данных в структуру пользователя, чтобы она теперь выглядела так:

  • id
  • profileName
  • profileIcon
  • profileSummary

Теперь, когда вызывается func loadUser(), происходит сбой с этим оператором:

Неустранимая ошибка: неожиданно обнаружен ноль при развертывании Необязательное значение: file

Как строится система: Когда приложение открывается в первый раз, оно создает 5 пустых профилей. Затем пользователь может «активировать» и заполнить эти профили, и он / она любит.

Я немного не уверен, как справиться с этой проблемой. Как я могу добавить новые точки данных в мою структуру, не вызывая приложение к sh?

Исходный код:

struct User: Codable {
  // Core user data
  let id:                     Int
  var profileName:            String
  var profileIcon:            String
  var profileSummary:         String
}

class DataManager: NSObject {

/// Used to encode and save user to UserDefaults
func saveUser(_ user: User) {

   if let encoded = try? JSONEncoder().encode(user) {
        UserDefaults.standard.set(encoded, forKey: "userProfile_\(user.id)")
        print("Saved user (ID: \(user.id)) successfully.")
   }

}

/// Used to decode and load user from UserDefaults
func loadUser(_ userID: Int) -> User {
    var user : User?

    if let userData = UserDefaults.standard.data(forKey: "userProfile_\(userID)"),
        let userFile = try? JSONDecoder().decode(User.self, from: userData) {
        user = userFile
        print("Loaded user (ID: \(user!.id)) successfully.")
    }

    return user!
}

 /// Used to create x empty userprofiles ready to be used
func createEmptyProfiles() {
    // May be changed, but remember to adjust UI
    var profilesAllowed = 5

    while profilesAllowed != 0 {
        print("Attempting to create empty profile for user with ID \(profilesAllowed)")

        let user = User(id: profilesAllowed, profileName: "", profileIcon: "", profileSummary: "Write a bit about your profile here..")

        self.saveUser(user)

        print("User with ID \(profilesAllowed) was created and saved successfully")

        // Substract one
        profilesAllowed -= 1
    }
}

 //MARK: - Delete profile
func deleteUser(user: User) -> Bool {

    var userHasBeenDeleted = false
    var userToDelete = user

    // Reset all values
    userToDelete.profileName = ""
    userToDelete.profileIcon = ""
    userToDelete.profileSummary = ""

    // Save the resetted user
    if let encoded = try? JSONEncoder().encode(userToDelete) {
        UserDefaults.standard.set(encoded, forKey: "userProfile_\(user.id)")
        print("User has now been deleted")
        userHasBeenDeleted = true
    }

    return userHasBeenDeleted

  }
}

1 Ответ

1 голос
/ 21 января 2020

Два варианта:

  1. Сделать profileSummary необязательным

    struct User: Codable {
      // Core user data
      let id:                     Int
      var profileName:            String
      var profileIcon:            String
      var profileSummary:         String?
    }
    

    Если ключ не существует, он будет проигнорирован.

  2. Реализация init(from decoder) и декодирование profileSummary с decodeIfPresent назначением пустой строки, если это не так.

Примечание:

Никогда try? в Codable контексте. Поймай ошибку и обработай ее. Ваш метод loadUser надежно завершает работу при возникновении ошибки. Безопасный способ - сделать метод throw и передать ошибки вызывающей стороне.

enum ProfileError : Error { case profileNotAvailable }

/// Used to decode and load user from UserDefaults
func loadUser(_ userID: Int) throws -> User {          
    guard let userData = UserDefaults.standard.data(forKey: "userProfile_\(userID)") else { throw ProfileError.profileNotAvailable }
    return try JSONDecoder().decode(User.self, from: userData)
}
...