【问题标题】:How to work with Firebase without allowing optional values如何在不允许可选值的情况下使用 Firebase
【发布时间】:2017-04-07 10:36:10
【问题描述】:

我是 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<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>
    }
}

我不知道具体原因,但那些问号感觉不太对劲,有时我会收到一些零指针错误,我认为我应该可以通过使用“好公民”技术来避免这种情况。

那么,有人知道我如何按照 Swift 最佳实践使用 Firebase?

【问题讨论】:

    标签: ios swift firebase firebase-realtime-database optional-parameters


    【解决方案1】:

    您希望允许您的 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,而另一些可以。这取决于您的需求。

    【讨论】:

    • 感谢您对如何使用可选项的出色解释和良好示例。我尝试了您提供给我的代码,但我必须进行一些更改才能使其工作: - FIRDataSnapshot 之后的问号:init?(快照:FIRDataSnapshot?) - [String : Any] 而不是 [String, Any] - [String : 细绳] ?? [:] 而不是 [String : String]:[:] 这些更改可以吗?如果是这样,您介意编辑您的答案以便我选择接受吗?
    • 已修复(我认为)。这些是我的回答中的错别字。
    • 我就是这么想的,你回答得真快:) 呢?在 init?(snapshot: FIRDataSnapshot?) 中,我可以把它放在那里吗?
    • 你指的是?这两个中的哪一个?在编写我的代码时,init 之后的那个应该在那里。我认为在FIRDataSnapshot 之后不需要?
    • 第二个。我不知道,xcode 引发了一个错误,让我把问号放在那里。
    【解决方案2】:

    首先,您可以在数据模型中包含可选项,只要您以后为它分配值即可。

    我建议使用ObserveSingleEvent(),您应该使用完成处理程序来简化它。如果您不知道完成处理程序:Link

    我推荐:

    • 不要将数据库引用放在你的类模型中,而不是使用Dictionary&lt;String, String&gt;? 只需使用[String: AnyObject]?

    • 公开您的帖子数组,以便可以在 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
    

    【讨论】:

      猜你喜欢
      • 2021-04-07
      • 2021-12-02
      • 2020-01-08
      • 2021-01-05
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 2016-11-18
      • 2019-02-03
      相关资源
      最近更新 更多