如何在不允许可选值的情况下使用 Firebase
How to work with Firebase without allowing optional values
我是 iOS 开发的新手,我知道在初始化对象时允许可选值不是 'good citizen' 技术。话虽如此,我读到过始终设置值是一种很好的做法,如下所示:
class Item{
var name: String
var color: String
init(name: String, color: String) {
self.name = name
self.color = color
}
}
这看起来很整洁,但是我怎样才能使用 Firebase 做类似的事情呢?看看我到目前为止得到了什么:
private func loadPosts(){
databaseHandle = ref.child("users/\(self.user.uid)/posts").observe(.value, with:{(snapshot) in
var newPosts = [Post]()
for itemSnapShot in snapshot.children {
let post = Post(snapshot: itemSnapShot as! FIRDataSnapshot)
newPosts.append(post!)
}
self.posts = newPosts
self.tableView.reloadData()
})
}
这个人放在我的 PostsViewController 中,我有我的 table 视图。这是我的模型:
class Post {
var ref: FIRDatabaseReference?
var title: String?
var answer: String?
var contentUrl: String?
var photoUrl: String?
var createdAt: String?
var feeling: String?
var kind: String?
var text: String?
var uid: String?
var measurements: Dictionary<String, String>?
//MARK: Initialization
init?(snapshot: FIRDataSnapshot){
ref = snapshot.ref
let data = snapshot.value as! Dictionary<String, Any>
title = data["title"]! as? String
answer = data["answer"] as? String
contentUrl = data["content_url"] as? String
photoUrl = data["photo_url"] as? String
createdAt = data["created_at"] as? String
feeling = data["feeling"] as? String
kind = data["kind"] as? String
text = data["text"] as? String
uid = data["uid"] as? String
measurements = data["measurements"] as? Dictionary<String, String>
}
}
我不知道为什么,但那些问号感觉不太对,我时不时会遇到一些 nil 指针错误,我想我应该可以通过使用 'good citizen' 来避免这种情况技术。
那么,有人知道如何按照 Swift 最佳实践使用 Firebase 吗?
您可以让 Post class 的属性为零,也可以不让。
如果你这样做了,那很好。您发布的代码允许其中任何一个为零。您只需要在每次需要时安全地访问每个 属性。
如果您不这样做,则不要将它们设为可选。然后在您的 init
中,您需要确保 none 的属性设置为 nil
,如果快照中没有值,则为每个属性设置一个默认值。
class Post {
var ref: FIRDatabaseReference
var title: String
var answer: String
var contentUrl: String
var photoUrl: String
var createdAt: String
var feeling: String
var kind: String
var text: String
var uid: String
var measurements: [String : String]
//MARK: Initialization
init?(snapshot: FIRDataSnapshot) {
if let data = snapshot.value as? [String : Any] {
self.ref = snapshot.ref
title = data["title"] as? String ?? ""
answer = data["answer"] as? String ?? ""
contentUrl = data["content_url"] as? String ?? ""
photoUrl = data["photo_url"] as? String ?? ""
createdAt = data["created_at"] as? String ?? ""
feeling = data["feeling"] as? String ?? ""
kind = data["kind"] as? String ?? ""
text = data["text"] as? String ?? ""
uid = data["uid"] as? String ?? ""
measurements = data["measurements"] as? [String : String] ?? [:]
} else {
return nil
}
}
}
注意这如何确保有正确的快照。如果快照中没有值,请注意如何为每个 属性 设置默认值。显然,您可以指定任何您希望的默认值。我以空字符串为例。
即使您希望允许属性为 nil
,您也应该至少更新您的代码以检查上面代码中的有效快照。
当然,您可以进行组合,其中一些属性不能 nil
而另一些可以。这取决于您的需要。
首先,您可以在数据模型中使用可选项,只要您以后为它赋值即可。
我建议使用 ObserveSingleEvent()
,您应该使用完成处理程序来简化操作。如果您不知道完成处理程序:Link
我推荐:
• 不要将数据库引用放入您的 class 模型中,而不是使用 Dictionary<String, String>?
只需使用 [String: AnyObject]?
• 创建您的 post 数组 public 以便它可以访问到表视图中。
示例如下:
class func getPosts(uid: String, _ completion: @escaping (_ posts: [Post]?, _ error: Error?) -> Void) {
//update inside users node
var posts = [Post]()
Firebase.databaseRef.child("users").child(uid).child("posts").observeSingleEvent(of: FIRDataEventType.value, with: { (dataSnapshot) in
guard let postsDictionary = dataSnapshot.value as? [String: AnyObject] else {
completion(nil, nil)
return
}
let n = postsDictionary.count
for postDictionary in postsDictionary {
let post = Post()
post.userID = uid
if let content = postDictionary.value["content"] as? String {
post.content = content
}
if let imageURL = postDictionary.value["imageURL"] as? String {
post.imageURL = imageURL
}
if let timeStamp = postDictionary.key as String! {
if let date = timeStamp.convertToDate() {
post.timeStamp = date
}
post.postIdentifier = timeStamp
}
posts.append(post)
if posts.count == n {
// Sort the array by the newest post
let sortedPosts = posts.sorted(by: { [=10=].timeStamp.compare(.timeStamp) == .orderedDescending })
completion(sortedPosts, nil)
}
}
}) { (error) in
completion(nil, error)
}
}
分配给 tableview 如下:
getPosts(uid: Current.user.userID!) { (posts, error) in
guard error == nil else {
print(error.debugDescription)
return
}
cell.label.text = posts[indexPath.item].content
我是 iOS 开发的新手,我知道在初始化对象时允许可选值不是 'good citizen' 技术。话虽如此,我读到过始终设置值是一种很好的做法,如下所示:
class Item{
var name: String
var color: String
init(name: String, color: String) {
self.name = name
self.color = color
}
}
这看起来很整洁,但是我怎样才能使用 Firebase 做类似的事情呢?看看我到目前为止得到了什么:
private func loadPosts(){
databaseHandle = ref.child("users/\(self.user.uid)/posts").observe(.value, with:{(snapshot) in
var newPosts = [Post]()
for itemSnapShot in snapshot.children {
let post = Post(snapshot: itemSnapShot as! FIRDataSnapshot)
newPosts.append(post!)
}
self.posts = newPosts
self.tableView.reloadData()
})
}
这个人放在我的 PostsViewController 中,我有我的 table 视图。这是我的模型:
class Post {
var ref: FIRDatabaseReference?
var title: String?
var answer: String?
var contentUrl: String?
var photoUrl: String?
var createdAt: String?
var feeling: String?
var kind: String?
var text: String?
var uid: String?
var measurements: Dictionary<String, String>?
//MARK: Initialization
init?(snapshot: FIRDataSnapshot){
ref = snapshot.ref
let data = snapshot.value as! Dictionary<String, Any>
title = data["title"]! as? String
answer = data["answer"] as? String
contentUrl = data["content_url"] as? String
photoUrl = data["photo_url"] as? String
createdAt = data["created_at"] as? String
feeling = data["feeling"] as? String
kind = data["kind"] as? String
text = data["text"] as? String
uid = data["uid"] as? String
measurements = data["measurements"] as? Dictionary<String, String>
}
}
我不知道为什么,但那些问号感觉不太对,我时不时会遇到一些 nil 指针错误,我想我应该可以通过使用 'good citizen' 来避免这种情况技术。
那么,有人知道如何按照 Swift 最佳实践使用 Firebase 吗?
您可以让 Post class 的属性为零,也可以不让。
如果你这样做了,那很好。您发布的代码允许其中任何一个为零。您只需要在每次需要时安全地访问每个 属性。
如果您不这样做,则不要将它们设为可选。然后在您的 init
中,您需要确保 none 的属性设置为 nil
,如果快照中没有值,则为每个属性设置一个默认值。
class Post {
var ref: FIRDatabaseReference
var title: String
var answer: String
var contentUrl: String
var photoUrl: String
var createdAt: String
var feeling: String
var kind: String
var text: String
var uid: String
var measurements: [String : String]
//MARK: Initialization
init?(snapshot: FIRDataSnapshot) {
if let data = snapshot.value as? [String : Any] {
self.ref = snapshot.ref
title = data["title"] as? String ?? ""
answer = data["answer"] as? String ?? ""
contentUrl = data["content_url"] as? String ?? ""
photoUrl = data["photo_url"] as? String ?? ""
createdAt = data["created_at"] as? String ?? ""
feeling = data["feeling"] as? String ?? ""
kind = data["kind"] as? String ?? ""
text = data["text"] as? String ?? ""
uid = data["uid"] as? String ?? ""
measurements = data["measurements"] as? [String : String] ?? [:]
} else {
return nil
}
}
}
注意这如何确保有正确的快照。如果快照中没有值,请注意如何为每个 属性 设置默认值。显然,您可以指定任何您希望的默认值。我以空字符串为例。
即使您希望允许属性为 nil
,您也应该至少更新您的代码以检查上面代码中的有效快照。
当然,您可以进行组合,其中一些属性不能 nil
而另一些可以。这取决于您的需要。
首先,您可以在数据模型中使用可选项,只要您以后为它赋值即可。
我建议使用 ObserveSingleEvent()
,您应该使用完成处理程序来简化操作。如果您不知道完成处理程序:Link
我推荐:
• 不要将数据库引用放入您的 class 模型中,而不是使用 Dictionary<String, String>?
只需使用 [String: AnyObject]?
• 创建您的 post 数组 public 以便它可以访问到表视图中。
示例如下:
class func getPosts(uid: String, _ completion: @escaping (_ posts: [Post]?, _ error: Error?) -> Void) {
//update inside users node
var posts = [Post]()
Firebase.databaseRef.child("users").child(uid).child("posts").observeSingleEvent(of: FIRDataEventType.value, with: { (dataSnapshot) in
guard let postsDictionary = dataSnapshot.value as? [String: AnyObject] else {
completion(nil, nil)
return
}
let n = postsDictionary.count
for postDictionary in postsDictionary {
let post = Post()
post.userID = uid
if let content = postDictionary.value["content"] as? String {
post.content = content
}
if let imageURL = postDictionary.value["imageURL"] as? String {
post.imageURL = imageURL
}
if let timeStamp = postDictionary.key as String! {
if let date = timeStamp.convertToDate() {
post.timeStamp = date
}
post.postIdentifier = timeStamp
}
posts.append(post)
if posts.count == n {
// Sort the array by the newest post
let sortedPosts = posts.sorted(by: { [=10=].timeStamp.compare(.timeStamp) == .orderedDescending })
completion(sortedPosts, nil)
}
}
}) { (error) in
completion(nil, error)
}
}
分配给 tableview 如下:
getPosts(uid: Current.user.userID!) { (posts, error) in
guard error == nil else {
print(error.debugDescription)
return
}
cell.label.text = posts[indexPath.item].content