当我使用任何新字段更新firebase firestore数据库时,它会立即杀死运行使用该数据的任何应用程序,并在下面的代码中显示致命错误。
我得到的错误是“fatalError:”无法用字典初始化类型餐馆[(名称:“测试”,可用性:“测试”,类别:“测试”)]
我希望能够在不让应用程序崩溃的情况下更新它。如果发生这种情况,他们必须删除并重新安装应用程序以使其再次工作,所以我认为它以某种方式在本地存储数据,但我找不到位置。
如何在不崩溃的情况下重置数据或重新加载?
抛出错误的文件(加载表数据时):
fileprivate func observeQuery() {
stopObserving()
guard let query = query else { return }
stopObserving()
listener = query.addSnapshotListener { [unowned self] (snapshot, error) in
guard let snapshot = snapshot else {
print("Error fetching snapshot results: \(error!)")
return
}
let models = snapshot.documents.map { (document) -> Restaurant in
if let model = Restaurant(dictionary: document.data()) {
return model
} else {
// Don't use fatalError here in a real app.
fatalError("Unable to initialize type \(Restaurant.self) with dictionary \(document.data())")
}
}
self.restaurants = models
self.documents = snapshot.documents
if self.documents.count > 0 {
self.tableView.backgroundView = nil
} else {
self.tableView.backgroundView = self.backgroundView
}
self.tableView.reloadData()
}
}
还有Restaurant.swift文件:
import Foundation
struct Restaurant {
var name: String
var category: String // Could become an enum
var availability: String // from 1-3; could also be an enum
var description: String
var dictionary: [String: Any] {
return [
"name": name,
"category": category,
"availability": availability,
"description": description
]
}
}
extension Restaurant: DocumentSerializable {
//Cities is now availability
static let cities = [
"In Stock",
"Back Order",
"Out of Stock"
]
static let categories = [
"Rock", "Boulder", "Grass", "Trees", "Shrub", "Barrier"
]
init?(dictionary: [String : Any]) {
guard let name = dictionary["name"] as? String,
let category = dictionary["category"] as? String,
let availability = dictionary["availability"] as? String,
let description = dictionary["description"] as? String
else { return nil }
self.init(name: name,
category: category,
availability: availability,
description: description
)
}
}
带有Document.Serializable代码的本地收集文件:
import FirebaseFirestore
// A type that can be initialized from a Firestore document.
protocol DocumentSerializable {
init?(dictionary: [String: Any])
}
final class LocalCollection<T: DocumentSerializable> {
private(set) var items: [T]
private(set) var documents: [DocumentSnapshot] = []
let query: Query
private let updateHandler: ([DocumentChange]) -> ()
private var listener: ListenerRegistration? {
didSet {
oldValue?.remove()
}
}
var count: Int {
return self.items.count
}
subscript(index: Int) -> T {
return self.items[index]
}
init(query: Query, updateHandler: @escaping ([DocumentChange]) -> ()) {
self.items = []
self.query = query
self.updateHandler = updateHandler
}
func index(of document: DocumentSnapshot) -> Int? {
for i in 0 ..< documents.count {
if documents[i].documentID == document.documentID {
return i
}
}
return nil
}
func listen() {
guard listener == nil else { return }
listener = query.addSnapshotListener { [unowned self] querySnapshot, error in
guard let snapshot = querySnapshot else {
print("Error fetching snapshot results: \(error!)")
return
}
let models = snapshot.documents.map { (document) -> T in
if let model = T(dictionary: document.data()) {
return model
} else {
// handle error
fatalError("Unable to initialize type \(T.self) with local dictionary \(document.data())")
}
}
self.items = models
self.documents = snapshot.documents
self.updateHandler(snapshot.documentChanges)
}
}
func stopListening() {
listener = nil
}
deinit {
stopListening()
}
}
答案 0 :(得分:1)
fatalError:&#34;无法用字典初始化餐厅类型[(名称:&#34;测试&#34;,可用性:&#34;测试&#34;,类别:&#34;测试&#34; )]
看起来非常简单 - 该词典没有足够的信息来创建一个Restaurant对象。
错误来自
if let model = Restaurant(dictionary: document.data()) {
return model
} else {
// Don't use fatalError here in a real app.
fatalError("Unable to initialize type \(Restaurant.self) with dictionary \(document.data())")
}
因为初始值设定项返回nil值,来自:
init?(dictionary: [String : Any]) {
guard let name = dictionary["name"] as? String,
let category = dictionary["category"] as? String,
let availability = dictionary["availability"] as? String,
let description = dictionary["description"] as? String
else { return nil }
self.init(name: name,
category: category,
availability: availability,
description: description
)
}
因为您的guard
返回nil,因为您在字典中没有 description 键。
要解决此问题,请在字典中添加 description 键,或者在缺少密钥时更改初始值设定项以使用默认说明。
例如,这是您的初始值设定项,重写为使用默认描述,用于描述条目缺失时
init?(dictionary: [String : Any]) {
guard let name = dictionary["name"] as? String,
let category = dictionary["category"] as? String,
let availability = dictionary["availability"] as? String
else { return nil }
let description = dictionary["description"] as? String
let defaultDescription: String = description ?? "No Description"
self.init(name: name,
category: category,
availability: availability,
description: defaultDescription
)
}