如何在不允许可选值的情况下使用Firebase

我是iOS开发的新手,我明白在初始化对象时允许可选值不是一种“好公民”技术。 话虽如此,我已经读过,总是设置值是一个好习惯,如下所示:

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里,我有桌子视图。 这是我的模特:

 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? //MARK: Initialization init?(snapshot: FIRDataSnapshot){ ref = snapshot.ref let data = snapshot.value as! Dictionary 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 } } 

我不确切知道为什么,但那些问号感觉不太正确,现在我得到一些零指针错误,我认为我应该能够通过使用“好公民”技术来避免。

那么,是否有人知道如何使用Firebase遵循Swift最佳实践?

要么您希望允许Post类的属性为nil,要么不允许。

如果你这样做,那没关系。 您发布的代码允许其中任何一个为零。 您只需在每次需要时安全地访问每个属性。

如果不这样做,那么不要将它们作为可选项。 然后在init ,如果快照中没有值,则需要确保没有任何属性设置为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() ,你应该使用完成处理程序来ObserveSingleEvent()它。 如果您不知道完成处理程序: 链接

我建议:

•不要将数据库引用放在类模型中,而不是使用Dictionary? 只使用[String: AnyObject]?

•使您的post数组公开,以便可以访问tableview。

这是一个例子:

 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: { $0.timeStamp.compare($1.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