我正在研究项目–使用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)
}
}
答案 0 :(得分:0)
有很多不同的方法可以使UI和数据库保持“同步”。在较高的层次上,有两个选择:
当前,您有一个tableView数据源
var posts: [Post] = []
由Firebase中的帖子填充。
从Firebase删除帖子时,也请从帖子中删除它,然后重新加载tableView。效果很好,但我更喜欢2)。
使用观察者,使用.childAdded,.childChanged或.childRemoved监视firebase中Posts节点中的更改。
使用这种方法,添加,更改或删除帖子时,该事件将传递给应用。发生这种情况时,您知道受影响的特定子节点,然后可以通过适当的操作更新tableView数据源,然后重新加载UI以反映这些更改。
假设您显示的是帖子列表,而用户删除了该列表。然后,您将从Firebase中删除该帖子,这将导致触发一个.childRemoved事件,其中包含已删除的帖子。然后,您可以在数据源中找到该帖子,将其删除并重新加载tableView。
有关更多信息,请参见Firebase Child Events。