如何在不允许可选值

时间:2017-04-06 21:55:53

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

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

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

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

2 个答案:

答案 0 :(得分:4)

您希望允许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并且有些属性可以组合。这符合您的需求。

答案 1 :(得分:0)

首先,您可以在数据模型中使用选项,只要您将来稍后为其指定值。

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

我建议:

•不要将数据库参考放在您的班级模型中,而不是使用Dictionary<String, String>?而只使用[String: AnyObject]?

•将您的帖子数组公开,以便可以访问表格视图。

这里的例子:

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