ios - 无法在 UserDefaults 中存储自定义对象数组
问题描述
我有一个名为Badge的自定义对象,并且我有一个要存储在 UserDefaults 中的 Badge ([Badge]) 数组。我相信我可能做错了。我能够构建我的代码,但在内部启动时出现以下错误getBadges()
:Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value**. Can someone help
。我已经尝试过这里的解决方案,但没有运气。
//
// Badge.swift
//
import Foundation
class Badge: NSObject {
var name: String
var info: String
var score: Float?
init(name: String, info: String, score: Float?) {
self.name = name
self.info = info
self.score = score
}
static func ==(lhs: Badge, rhs: Badge) -> Bool {
return lhs.name == rhs.name
}
func encodeWithCoder(coder: NSCoder) {
coder.encode(self.name, forKey: "name")
coder.encode(self.info, forKey: "info")
}
}
//
// BadgeFactory.swift
//
import Foundation
class BadgeFactory {
let defaults: UserDefaults
var badges: [Badge] = []
var userBadges: [Badge] = []
static let b = "Badges"
init() {
self.defaults = UserDefaults.standard
self.userBadges = self.getBadges()
}
func addBadges(score: Float) -> [Badge]
{
var new_badges: [Badge] = []
for badge in self.badges {
if (!self.checkIfUserHasBadge(badge: badge) && badge.score != nil && score >= badge.score!) {
new_badges.append(badge)
self.userBadges.append(badge)
}
}
self.defaults.set(self.userBadges, forKey: BadgeFactory.b)
return new_badges
}
func checkIfUserHasBadge(badge: Badge) -> Bool
{
if self.badges.contains(badge) {
return true
}
else {
return false
}
}
func getBadges() -> [Badge] {
return self.defaults.array(forKey: BadgeFactory.b) as! [Badge]
}
func loadDefaultBadges() {
// Score badges.
self.badges.append(Badge(name: "Badge1", info: "My cool badge", score: 80))
self.badges.append(Badge(name: "Badge2", info: "My second cool badge", score: 90))
}
}
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var bf = BadgeFactory()
bf.getBadges()
bf.addBadges(score: 85)
}
}
解决方案
此错误的原因位于您的getBadges()
函数中:
func getBadges() -> [Badge] {
return self.defaults.array(forKey: BadgeFactory.b) as! [Badge]
}
随着as!
您隐式展开您期望的数组。但是只要你没有向这个 userDefaults 键写入数据,array(forKey:)
就会一直返回nil
!
因此,您需要在此处使用安全展开,例如:
return self.defaults.array(forKey: BadgeFactory.b) as? [Badge] ?? []
.
但这不是唯一的问题。就像您已经偶然发现的那样,您仍然需要实现您发布的线程的解决方案。自定义 NSObjects 不能在没有编码的情况下存储在默认值中。
您需要NSCoding protocol
在您的Badge
类中实现(init(coder:)
缺少)并使用 Unarchiver 进行读取,以及使用 Archiver 将数据写入默认值。
所以你的代码应该是这样的:
class Badge: NSObject, NSCoding {
var name: String
var info: String
var score: Float?
init(name: String, info: String, score: Float?) {
self.name = name
self.info = info
self.score = score
}
required init?(coder: NSCoder) {
self.name = coder.decodeObject(forKey: "name") as! String
self.info = coder.decodeObject(forKey: "info") as! String
self.score = coder.decodeObject(forKey: "score") as? Float
}
static func ==(lhs: Badge, rhs: Badge) -> Bool {
return lhs.name == rhs.name
}
func encodeWithCoder(coder: NSCoder) {
coder.encode(self.name, forKey: "name")
coder.encode(self.info, forKey: "info")
coder.encode(self.score, forKey: "score")
}
}
class BadgeFactory {
...
func addBadges(score: Float) -> [Badge] {
...
let data = NSKeyedArchiver.archivedData(withRootObject: self.userBadges)
defaults.set(data, forKey: BadgeFactory.b)
...
}
func getBadges() -> [Badge] {
guard let data = defaults.data(forKey: BadgeFactory.b) else { return [] }
return NSKeyedUnarchiver.unarchiveObject(ofClass: Badge, from: data) ?? []
}
...
}
推荐阅读
- firebase - 如何授予基于其他集合的用户的集合访问权限?
- ios - 旧版 VoIP API 在 iOS 11/12/13/14 中是否仍然可用?
- python - 从字符串中提取澳大利亚电话号码
- r - Chrome debugging port not open after 10 seconds
- asp.net-mvc - OWIN + 自定义中间件 + MVC
- ios - 在 Swift 中单击 NSObject 内的 tableView 中的项目时,如何在 NSObject 类内的 UIViews 或 UIViewController 之间正确切换?
- microsoft-translator - 200 万个字符的限制是否包括调整和测试数据集?
- swift - 如何在用户操作时动态更新 UICollectionViewCompositionalLayout(即滑动 UISlider)
- drawing - 是否可以使用 Photoshop 在图像中搜索图形符号?
- data-distribution-service - OpenSplice:创建参与者失败