我有一个名为 Badge 的自定义对象,我有一个 Badges ([Badge]) 数组,我想将它们存储在 UserDefaults 中。我相信我可能做错了。我能够构建我的代码,但在 getBadges()
中启动时出现以下错误:Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value**. Can someone help
。我已经尝试过 here 的解决方案,但没有成功。
//
// 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)
}
}
答案 0 :(得分:1)
此错误的原因位于您的 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) ?? []
}
...
}
答案 1 :(得分:0)
错误可能来自您 viewDidLoad 中的这一行:
bf.getBadges()
这将尝试执行 self.defaults.array(forKey: BadgeFactory.b) as! [Badge]
此时 UserDefaults 为空(因为您在调用 .addBadges
或为键提供任何其他值之前这样做了)。因此,self.defaults.array(forKey: BadgeFactory.b)
将评估为 nil,并且强制转换 as! [Badge]
将在运行时失败并显示您提供的消息。
为了解决我会像这样调整函数:
func getBadges() -> [Badge] {
return (self.defaults.array(forKey: BadgeFactory.b) as? [Badge]) ?? []
}