ios - 无法让 Firestore 将快照文档转换为“照片”对象
问题描述
我在将getPhotos
使用 Firebase 实时数据库的方法迁移到getPhotos1
使用 Firestore 时遇到问题,但由于某种原因无法将文档快照导入getPhotos1
对象Photos1
。
这是我getPhotos
使用 Firebase 实时数据库的方法:
static func getPhotos (completion: @escaping ([Photo]) -> Void) {
//Getting a reference to the database
let dbRef = Database.database().reference()
//Make the db call
dbRef.child("photos").observeSingleEvent(of: .value) { (snapshot) in
//Declare an array to hold the photos
var retrievedPhotos = [Photo]()
//Get the list of snapshots
let snapshots = snapshot.children.allObjects as? [DataSnapshot]
if let snapshots = snapshots {
//Loop through each snapshot and parse out the photos
for snap in snapshots {
//Try to create a photo from a snapshot
let p = Photo(snapshot: snap)
//If successful, then add it to our array
if p != nil {
retrievedPhotos.insert(p!, at: 0)
}
}
}
//After parsing the snapshots, call the completion closure
completion(retrievedPhotos)
}
}
这是它的对象
import Foundation
import RealmSwift
import FirebaseDatabase
import Firebase
class Photo: Object {
@objc dynamic var photoId:String?
@objc dynamic var byId:String?
@objc dynamic var byUsername:String?
@objc dynamic var date:String?
@objc dynamic var url:String?
@objc dynamic var postId:String?
override static func primaryKey() -> String? {
return "photoId"
}
override static func indexedProperties() -> [String] {
return ["byUsername"]
}
convenience init?(snapshot:DataSnapshot){
self.init ()
//Photo data
let photoData = snapshot.value as? [String:String]
if let photoData = photoData {
let photoId = snapshot.key
let byId = photoData["byId"]
let byUsername = photoData["byUsername"]
let date = photoData["date"]
let url = photoData["url"]
let postId = photoData["postId"]
guard byId != nil && byUsername != nil && date != nil && url != nil && postId != nil else {
return nil
}
self.photoId = photoId
self.byId = byId
self.byUsername = byUsername
self.date = date
self.url = url
self.postId = postId
}
}
}
这是我getPhotos1
使用 Firestore 的方法,但它不起作用:
static func getPhotos1 (completion: @escaping ([Photo1]) -> Void) {
//Get a Firebase reference
let db = Firestore.firestore()
db.collection("posts").getDocuments() {snapshot, error in
//Declare an array to hold the photos
var retrievedPhotos = [Photo1]()
if error == nil && snapshot != nil {
for document in snapshot!.documents {
let p = Photo1(snapshot: document)
print(p!)
if p != nil {
retrievedPhotos.insert(p!, at: 0)
//print("retrievedPhotos: \(retrievedPhotos)")
}
}
}
//After parsing the snapshots, call the completion closure
completion(retrievedPhotos)
}
}
这就是它的对象
class Photo1: Object {
@objc dynamic var photoId:String?
@objc dynamic var byId:String?
@objc dynamic var byUsername:String?
@objc dynamic var date:String?
@objc dynamic var url:String?
@objc dynamic var postId:String?
override static func primaryKey() -> String? {
return "photoId"
}
override static func indexedProperties() -> [String] {
return ["byUsername"]
}
convenience init?(snapshot:DocumentSnapshot){
self.init ()
//Photo data
let photoData = snapshot.data() as? [String:String]
if let photoData = photoData {
let photoId = snapshot.documentID
let byId = photoData["byId"]
let byUsername = photoData["byUsername"]
let date = photoData["date"]
let url = photoData["url"]
let postId = photoData["postId"]
guard byId != nil && byUsername != nil && date != nil && url != nil && postId != nil else {
return nil
}
self.photoId = photoId
self.byId = byId
self.byUsername = byUsername
self.date = date
self.url = url
self.postId = postId
}
}
}
10/1 编辑:更新了 getPhoto1 方法。
static func getPhotos1 (completion: @escaping ([Photo1]) -> Void) {
//Get a Firebase reference
let db = Firestore.firestore()
db.collection("posts").getDocuments() { (snapshot, error) in
//Declare an array to hold the photos
var retrievedPhotos = [Photo1]()
print("This is snapshot: \(String(describing: snapshot))")
if error == nil && snapshot != nil {
for document in snapshot!.documents {
let documentData = document.data()
print("This is DocData: \(documentData)")
let p = Photo1(snapshot: documentData)
print("This is p: \(p)")
if p != nil {
retrievedPhotos.insert(p!, at: 0)
print("retrievedPhotos: \(retrievedPhotos)")
}}}
//After parsing the snapshots, call the completion closure
completion(retrievedPhotos)
}}
但是我收到了这个错误:
Cannot convert value of type '[String : Any]' to expected argument type 'DocumentSnapshot'
提前感谢您的建议。
我试图搜索关于此的先前线程,虽然有一些,但我无法弄清楚,因为它们不是 Swift 特定的。
解决方案
问题中的代码存在许多问题;三种不同的 API(Firebase RealTime Database、Firestore 和 Realm),我认为这可能会造成一些混乱。
让我们用一个直接的 Firestore 答案切入正题。此代码将读取 Firestore 集合中的文档,根据该数据创建 PhotoClass 对象并将它们存储在数组中。假设结构是这样的
photos //a collection
photo_0 //a document
byUserName: "Henry"
byId: "uid_0"
photo_1
byUserName: "George"
byId: "uid_1"
这是一个 PhotoClass - 我将属性默认为空字符串而不是 nils,以减少处理 nils 的需要。由于我们没有使用 Realm,我还删除了 Object 定义并将 vars 更改为 Swift vars 而不是 Realm 所需的 ObjC vars(@objc 动态)
class PhotoClass {
var photoId = ""
var byId = ""
var byUsername = ""
//var date:String?
//var url:String?
//var postId:String?
init(withDocumentSnapshot: DocumentSnapshot) {
self.photoId = withDocumentSnapshot.documentID
self.byUsername = withDocumentSnapshot.get("userName") as? String ?? "No User Name"
self.byId = withDocumentSnapshot.get("byId") as? String ?? "No uid"
}
}
请注意,如果读取属性为零,我将默认值设置为已知字符串。这样,如果属性丢失或为零,应用程序就不会崩溃。如果你想使用 nil 值,那很酷,但你必须通过安全地使用它们来保护你的代码。
然后是一个存储照片的数组
var photosArray = [PhotoClass]()
然后代码读取照片节点中的所有文档,创建 PhotoClass 对象并填充数组
func readAllPhotos() {
let photosCollection = self.db.collection("photos")
photosCollection.getDocuments(completion: { snapshot, err in
if let err = err {
print(err.localizedDescription)
return
}
for doc in snapshot!.documents {
let photo = PhotoClass(withDocumentSnapshot: doc)
self.photosArray.append(photo)
}
})
}
再次注意,有代码可以检查错误并保护应用程序,以防找不到节点或发生其他错误。
推荐阅读
- openshift - 如何在 minishift 上启用指标?
- ios - PHCollection:获取所有专辑,按最近编辑的排序
- java - 如何等待 JFrame 线程从 JavaFX 应用程序内部完成?
- javascript - 〜5如何返回-6?
- java - 为什么 Collections#shuffle 不使用 ThreadLocalRandom?
- r - 重塑数据框 - 世界银行数据
- java - 我无法导入 android.widget
- chess - 船上使用 Minimax 和 alpha beta
- javascript - 即使用户已经在浏览器上登录,LinkedIn Web OAuth 2.0 验证也需要输入密码
- c - C中字符串指针的增加值