从Firebase数据库中删除数据并更新视图

时间:2020-09-19 17:15:26

标签: ios swift firebase firebase-realtime-database

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

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

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

1 个答案:

答案 0 :(得分:0)

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

当前,您有一个tableView数据源

var posts: [Post] = []

由Firebase中的帖子填充。

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

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

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

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

有关更多信息,请参见Firebase Child Events