当 Firebase 中的数据发生变化时,Swift CollectionView.reload 数据不起作用?
Posted
技术标签:
【中文标题】当 Firebase 中的数据发生变化时,Swift CollectionView.reload 数据不起作用?【英文标题】:Swift CollectionView.reload data not working when data changes in Firebase? 【发布时间】:2018-06-19 07:55:50 【问题描述】:我目前有这个工作代码,它从 Firebase 中的 users
位置读取,其中包含每个用户的所有用户个人资料信息。我正在使用从 Firebase 返回的快照(数据)来构建我的数组并在 CollectionView
中显示用户。
我预期的行为(没有发生)是,当 Firebase 中 user
属性的值发生更改时(例如,online
状态更改为“离线”),这应该被推送到我的应用程序这样CollectionView
就会更新,因此不会显示刚刚“离线”的用户。
我在下面使用了正确的 Firebase 查询吗?
self.REF_USERS.observeSingleEvent(of: .value , with: (snapshot) in
guard let usersSnapshot = snapshot.children.allObjects as? [DataSnapshot] else return
for user in usersSnapshot
let discoverable = user.childSnapshot(forPath: "discoverable").value as! Bool
if user.key == key && discoverable == true
let uid = user.key
let name = user.childSnapshot(forPath: "name").value as! String
let email = user.childSnapshot(forPath: "email").value as! String
let profilePictureURL = user.childSnapshot(forPath: "profilePictureURL").value as! String
let birthday = user.childSnapshot(forPath: "birthday").value as! String
let firstName = user.childSnapshot(forPath: "firstName").value as! String
let lastName = user.childSnapshot(forPath: "lastName").value as! String
let gender = user.childSnapshot(forPath: "gender").value as! String
let discoverable = user.childSnapshot(forPath: "discoverable").value as! Bool
let online = user.childSnapshot(forPath: "online").value as! Bool
let discoveryPrefs = user.childSnapshot(forPath: "discoveryPrefs").value as! [String : Any]
let dictionary: [String : Any] = ["uid": uid, "name": name, "email": email, "profilePictureURL": profilePictureURL, "birthday": birthday, "firstName": firstName, "lastName": lastName, "gender": gender, "discoverable": discoverable, "online": online, "discoveryPrefs": discoveryPrefs]
let user = User(uid: uid, dictionary: dictionary)
users.append(user)
//end if
//end for
//filter out "remove" current user from array
let filteredUsers = users.filter( (user: User) -> Bool in return !user.uid.contains(uid) )
handler(filteredUsers.shuffled(), true)//return a shuffled version of the array via handler
)//end FIR snapshot call
这就是我使用上面的代码加载/重新加载数据的方式:
DataService.run.getUsersAtVenue(forVenueLocation: location, forUid: userId) (users, successBool) in
if successBool
self.users = users
self.collectionView.reloadData()
Utilities.run.dismissSVHUD(delay: 0.5)
【问题讨论】:
当用户离线时你从online
得到什么? True/False
?
我目前正在将discoverable
的值更改为true
或false
,此字段指定是否应在collectionview 上显示用户。 online
也一样,true
或 false
【参考方案1】:
你在主线程中,users
改变了吗?试着把它放进去:
DispatchQueue.main.async
if users.count > 0
self.users = users
self.collectionView.reloadData()
Utilities.run.dismissSVHUD(delay: 0.5)
【讨论】:
这会加载 collectioview,但是当 Firebase 中的数据发生变化时它不会更新。 评论您的加载方法并分配users
值以测试您的收藏视图是否正常工作。如果没有问题,请取消注释 load 方法,然后检查可能多次加载的潜在原因,并且您的 users variable.count 不是 0,但对于下一轮调用,它被设置为 nil
或其他。你能检查一下你的加载用户方法被调用了多少次吗?【参考方案2】:
Roggie,您需要注册一个观察者,以便在特定“用户”节点(“用户”位置下的子节点)发生更改时接收通知。此代码应如下所示
_refHandleUserChanged = ref.child("users").observe(.childChanged, with: (snapshot) in
guard let changedUserIndex = self.userSnapshots.index $0.key == snapshot.key else return
self.userSnapshots[changedUserIndex] = snapshot
self.userCollectionView.reloadRows(at: [IndexPath(row: changedUserIndex, section: 0)], with: .automatic)
)
其中“ref”是对您的 Firebase 数据库的引用,“_refHandleUserChanged”是您当前类(可能是您的 View Controller 类)的实例 var 属性。然后,当您的实例被取消初始化时,您应该取消注册/删除此观察者,如下面的代码。
deinit
ref.child("users").removeObserver(withHandle: _refHandleUserChanged)
【讨论】:
您对注册“观察员”的反馈很有道理。我只是想了解我的代码所需的更改。我需要将“观察者”部分添加到我的cellForItemAt
吗?如果没有,那么在哪里?另外,var _refHandleUserChanged
会是我当前的 ViewController 的一个实例,它被称为DiscoverVC
?。你能给我指点一些在线教程吗?
您的 DiscoverVC 是否符合 UICollectionViewDataSource?如果是这样,您应该在 DiscoverVC 类中创建一个单独的方法,例如称为 configureDatabase,其中包含“ref = Database.database().reference()”和上面的“观察者注册”代码。然后在 viewDidLoad 方法中调用此方法。当然,您需要将“ref”和“_refHandleUserChanged”声明为 DiscoverVC 类的 var 属性,如下所示:“private var ref: DatabaseReference!” & "私有变量 _refHandleUserChanged: DatabaseHandle!"
DiscoverVC
确实符合UICollectionViewDataSource
,我已经创建了建议的函数,但是我收到了一个错误Use of unresolved identifier '_refHandleUserChanged'
。这个变量应该是什么?还有Anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean 'snapshot'?
Replace '$0' with 'snapshot'
'_refHandleUserChanged' 应在 DiscoverVC 类的顶部声明,如“private var ref: DatabaseReference!”。请注意,我假设您的 var 属性“userSnapshots”加载了 Firebase 数据库中的用户记录。然后将此属性用作数据源来填充您的 CollectionView。您可以查看这个简短而有用的课程udacity.com/course/firebase-in-a-weekend-by-google-ios--ud0351【参考方案3】:
我对小数据集所做的是在你拥有所有新数据后完成completionBlock。
topViewController 是 CollectionView 如果将其转换为自定义的 collectionView 然后调用collectionview.reloadData。
所有这些都嵌入到主队列中。
您很可能在取回数据之前重新加载
【讨论】:
以上是关于当 Firebase 中的数据发生变化时,Swift CollectionView.reload 数据不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
当 Kotlin 中的数据发生变化时,如何在 RecyclerView 中重新绑定项目?
每当firebase发生任何变化时,自动向所有用户发送通知[关闭]