从Firebase数据库中删除数据并更新视图 [英] Delete data from Firebase Database and update View

查看:69
本文介绍了从Firebase数据库中删除数据并更新视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究项目–使用Firebase的社交网络应用程序.我的照片库中有用户上传的照片.用户删除照片时,它会从数据库中删除,但仍会显示在视图上,直到应用重新启动为止.如何立即在视图上显示数据库更改?感谢任何帮助!

I'm working on study project – social network app using Firebase. I have photo gallery with photos uploded by the user. When user deletes a photo it deletes from database but still showing on the view until the app restarts. How I can instantly show database changes on the view? Appreciate any help!

MyPostApi

MyPostApi

class MyPostsApi {
var REF_MYPOSTS =  Database.database().reference().child("myPosts")

func fetchMyPosts(userId: String, completion: @escaping (String) -> Void) {
    REF_MYPOSTS.child(userId).observe(.childAdded, with: {
        snapshot in
        completion(snapshot.key)
    })
}

func fetchCountMyPosts(userId: String, completion: @escaping (Int) -> Void) {
    REF_MYPOSTS.child(userId).observe(.value, with: {
        snapshot in
        let count = Int(snapshot.childrenCount)
        completion(count)
    })
}

PostApi

class PostApi {
var REF_POSTS =  Database.database().reference().child("posts")

func observePosts(completion: @escaping (Post) -> Void) {
    REF_POSTS.observe(.childAdded) { (snapshot: DataSnapshot) in
        if let dict = snapshot.value as? [String: Any] {
            let newPost = Post.transformPostPhoto(dict: dict, key: snapshot.key)
            completion(newPost)
            
        }
    }
}

func observeTopPosts(completion: @escaping (Post) -> Void) {
    REF_POSTS.queryOrdered(byChild: "likeCount").observeSingleEvent(of: .value, with: {
        snapshot in
        let arraySnapshot = (snapshot.children.allObjects as! [DataSnapshot]).reversed()
        arraySnapshot.forEach({ (child) in
            if let dict = child.value as? [String: Any] {
                let post = Post.transformPostPhoto(dict: dict, key: child.key)
                completion(post)
            }
        })
    })
}


func observePost(withId id: String, completion: @escaping (Post) -> Void) {
    REF_POSTS.child(id).observeSingleEvent(of: DataEventType.value, with: {
        snapshot in
        if let dict = snapshot.value as? [String: Any] {
            let post = Post.transformPostPhoto(dict: dict, key: snapshot.key)
            completion(post)
        }
    })
}

 func observeLikeCount(withPostId id: String, completion: @escaping (Int) -> Void) {
        REF_POSTS.child(id).observe(.childChanged, with: {
        snapshot in
        if let value = snapshot.value as? Int {
            completion(value)
        }
    })
}

func incrementLikes(postId: String, onSuccess: @escaping (Post) -> Void, onError: @escaping (_ errorMessage: String?) -> Void) {
    let postRef = Api.Post.REF_POSTS.child(postId)
    postRef.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
        if var post = currentData.value as? [String : AnyObject], let uid = Api.User.CURRENT_USER?.uid {
            var likes: Dictionary<String, Bool>
            likes = post["likes"] as? [String : Bool] ?? [:]
            var likeCount = post["likeCount"] as? Int ?? 0
            if let _ = likes[uid] {
                likeCount -= 1
                likes.removeValue(forKey: uid)
            } else {
                likeCount += 1
                likes[uid] = true
            }
            post["likeCount"] = likeCount as AnyObject?
            post["likes"] = likes as AnyObject?
            
            currentData.value = post
            
            return TransactionResult.success(withValue: currentData)
        }
        return TransactionResult.success(withValue: currentData)
    }) { (error, committed, snapshot) in
        if let error = error {
            onError(error.localizedDescription)
        }
        if let dict = snapshot?.value as? [String: Any] {
            let post = Post.transformPostPhoto(dict: dict, key: snapshot!.key)
            onSuccess(post)
        }
    }
}
}

ProfileVC

ProfileVC

class ProfileViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    var user: User!
    var posts: [Post] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.dataSource = self
        collectionView.delegate = self
        fetchUser()
        fetchMyPosts()
        
        
    }
    
    func fetchUser() {
        Api.User.observeCurrentUser { (user) in
            self.user = user
            self.navigationItem.title = user.username
            self.collectionView.reloadData()
        }
    }
    
    func fetchMyPosts() {
        guard let currentUser = Api.User.CURRENT_USER else {
            return
        }
        Api.MyPosts.REF_MYPOSTS.child(currentUser.uid).observe(.childAdded, with: {
            snapshot in
            Api.Post.observePost(withId: snapshot.key, completion: {
                post in
                self.posts.append(post)
                self.collectionView.reloadData()
                
            })
        })
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "Profile_SettingSegue" {
            let settingVC = segue.destination as! SettingTableViewController
            settingVC.delegate = self
        }
        
        if segue.identifier == "Profile_DetailSegue" {
            let detailVC = segue.destination as! DetailViewController
            let postId = sender as! String
            detailVC.postId = postId
        }
    }
    
}

extension ProfileViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return posts.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCollectionViewCell", for: indexPath) as! PhotoCollectionViewCell
        let post = posts[indexPath.row]
        cell.post = post
        cell.delegate = self
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerViewCell = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderProfileCollectionReusableView", for: indexPath) as! HeaderProfileCollectionReusableView
        if let user = self.user {
            headerViewCell.user = user
            headerViewCell.delegate2 = self
        }
        return headerViewCell
    }
}
extension ProfileViewController: HeaderProfileCollectionReusableViewDelegateSwitchSettingVC {
    func goToSettingVC() {
        performSegue(withIdentifier: "Profile_SettingSegue", sender: nil)
    }
}
extension ProfileViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 1.74
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.frame.size.width / 3 - 1, height: collectionView.frame.size.width / 3 - 1)
    }
}
extension ProfileViewController: SettingTableViewControllerDelegate {
    func updateUserInfo() {
        self.fetchUser()
    }
}
extension ProfileViewController: PhotoCollectionViewCellDelegate {
    func goToDetailVC(postId: String) {
        performSegue(withIdentifier: "Profile_DetailSegue", sender: postId)
    }
}

推荐答案

有很多不同的方法可以使UI和数据库保持同步".在较高的层次上,有两个选择:

There are many different approaches to keep the UI and database 'in sync'. At a high level here's two options:

当前,您有一个tableView数据源

Currently, you have a tableView dataSource

var posts: [Post] = []

从Firebase中填充帖子.

which is populated from Firebase with posts.

  1. 从Firebase删除帖子时,也请从帖子中删除它,然后重新加载tableView.效果很好,但我更喜欢2).

  1. When deleting the post from Firebase, also remove it from posts then re-load your tableView. This works pretty well but I like 2) better.

使用观察者,使用.childAdded,.childChanged或.childRemoved监视firebase中Posts节点中的更改.

Using observers, watch for changes in your Posts node in firebase using .childAdded, .childChanged or .childRemoved.

使用这种方法,添加,更改或删除帖子时,该事件将传递到应用程序.发生这种情况时,您知道受影响的特定子节点,然后可以通过适当的操作更新tableView数据源,然后重新加载UI以反映这些更改.

With this approach, when a post is added, changed or removed, that event will be passed to the app. When it occurs you know the specific child node that was affected and can then update your tableView Datasource with the appropriate action and then reload the UI to reflect those changes.

假设您显示的是帖子列表,而用户删除了该列表.然后,您将从Firebase中删除该帖子,这将导致触发一个.childRemoved事件,其中包含已删除的帖子.然后,您可以在数据源中找到该帖子,将其删除并重新加载tableView.

Suppose you are showing a list of posts, and the user delete's one. You would then delete that post from Firebase which would cause a .childRemoved event to fire containing the post that was removed. You can then locate that post in your datasource, remove it and reload your tableView.

请参阅 Firebase子事件以了解更多信息

这篇关于从Firebase数据库中删除数据并更新视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆