How to work with Firebase without allowing optional values

谁说我不能喝 提交于 2019-12-07 07:20:28

Either you wish to allow the properties of your Post class to be nil or you don't.

If you do, that's fine. The code you posted allows any of them to be nil. You just need to safely access each property every time you need it.

If you don't, then don't make them optional. Then in your init you need to ensure none of the properties are set to nil by giving each a default if there is no value in the snapshot.

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

Note how this ensures there is a proper snapshot. Note how a default value is set to each property if there is no value in the snapshot. Obviously you can assign any default you wish. I use the empty string as an example.

Even if you want to allow the properties to be nil, you should at least update your code to check for a valid snapshot like in the code above.

Of course you can have a combination where some properties can't be nil and some can. That's up to your needs.

First it is fine for you to have optionals in your data model, as long as you assign value to it later on in the future.

I would recommend to use ObserveSingleEvent() and you should make use of completion handler to make it easy. If you don't know completion handler: Link

I recommend:

• not to put database ref in your class model, and instead of using Dictionary<String, String>? just use [String: AnyObject]?

• make your post array public so that it can be accessed into the tableview.

Here's example:

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)
    }
}

Assigning to tableview be like:

getPosts(uid: Current.user.userID!) { (posts, error) in
        guard error == nil else {
            print(error.debugDescription)
            return
        }
        cell.label.text = posts[indexPath.item].content
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!