Когда я изменил поле в базе данных обзора в Firestore (и, очевидно, также изменил его в коде), приложение вылетает. В окне журнала написано:
невозможно инициализировать тип Просмотр со словарем [...]
(в этом словаре отображается старое поле, хотя оно не существуетв базе данных больше!). Похоже, что приложение хранит старые данные где-то локально и не извлекает новые данные из базы данных.
localCollection.swift
public protocol DocumentSerializable {
init?(document: QueryDocumentSnapshot)
init?(document: DocumentSnapshot)
var documentID: String { get }
var documentData: [String: Any] { get }
}
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()
}
}
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(document: document) {
return model
} else {
// handle error
print("Imen")
fatalError("Unable to initialize type \(T.self) with dictionary \(document.data())")
}
}
self.items = models
self.documents = snapshot.documents
self.updateHandler(snapshot.documentChanges)
}
}
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 stopListening() {
listener?.remove()
listener = nil
}
deinit {
stopListening()
}
}
Review.swift
struct Review {
var documentID: String
var restaurantID: String
var restaurantName: String
var stars: Bool
var userInfo: User
}
extension Review : DocumentSerializable {
var documentData: [String : Any] {
return [
"restaurant ID": restaurantID,
"restaurant Name": restaurantName,
"stars": stars,
"User Info": userInfo.documentData
]
}
private init?(documentID: String, dictionary: [String : Any]) {
guard let restaurantID = dictionary["restaurant ID"] as? String,
let restaurantName = dictionary["restaurant Name"] as? String,
let stars = dictionary["stars"] as? Bool,
let userInfo = dictionary["userInfo"] as? [String: Any] else {
return nil }
guard let user = User(dictionary: userInfo) else {
return nil }
self.init(documentID: documentID,
restaurantID: restaurantID,
restaurantName: restaurantName,
stars: stars,
userInfo: user)
}
public init?(document: QueryDocumentSnapshot) {
self.init(documentID: document.documentID, dictionary: document.data())
}
public init?(document: DocumentSnapshot) {
guard let data = document.data() else { return nil }
self.init(documentID: document.documentID, dictionary: data)
}
public init?(
restaurantID: String,
restaurantName: String,
stars: Bool,
userInfo: User) {
let document = Firestore.firestore().reviews.document()
self.init(documentID: document.documentID,
restaurantID: restaurantID,
restaurantName: restaurantName,
stars: stars,
userInfo: userInfo)
}
}
User.swift
struct User {
var userID: String
var name: String
var photoURL: URL
}
extension User: DocumentSerializable {
var documentID: String {
return userID
}
// The default URL for profile images.
static let defaultPhotoURL =
URL(string:"")!https://firebasestorage.googleapis.com/v0/b/Restaurant/o/x.png?alt=media&token=7e95c1fb-f402-4611-90d4-cb9c2362fbff
// Initializes a User from document snapshot data.
private init?(documentID: String, dictionary: [String : Any]) {
guard let userID = dictionary["UserID"] as? String else { return nil }
precondition(userID == documentID)
self.init(dictionary: dictionary)
}
public init?(dictionary: [String: Any]) {
guard let userID = dictionary["UserID"] as? String,
let name = dictionary["Name"] as? String,
let photoURLString = dictionary["PhotoURL"] as? String else { return nil }
guard let photoURL = URL(string: photoURLString) else { return nil }
self.init(userID: userID, name: name, photoURL: photoURL)
}
public init?(document: QueryDocumentSnapshot) {
self.init(documentID: document.documentID, dictionary: document.data())
}
public init?(document: DocumentSnapshot) {
guard let data = document.data() else { return nil }
self.init(documentID: document.documentID, dictionary: data)
}
/// Returns a new User, providing a default name and photoURL if passed nil or left unspecified.
public init(userID: String,
name: String? = "Eater",
photoURL: URL? = User.defaultPhotoURL) {
self.init(userID: userID,
name: name ?? "eater",
photoURL: photoURL ?? User.defaultPhotoURL)
}
public init() {
let uid = UUID().uuidString
self.init(userID: uid)
}
/// A user object's representation in Firestore.
public var documentData: [String: Any] {
return [
"UserID": userID,
"Name": name,
"PhotoURL": photoURL.absoluteString
]
}
}