Swift iOS - 如何在 Firebase Observer .childAdded 之外重新加载 TableView 以过滤掉重复值?
Swift iOS -How To Reload TableView Outside Of Firebase Observer .childAdded to Filter Out Duplicate Values?
我有一个带有 2 个选项卡的 tabBar 控制器:包含 ClassA 的 tabA 和包含 ClassB 的 tabB。我在 tabA/ClassA 中将数据发送到 Firebase 数据库,并在 tabB/ClassB 中观察数据库,我在其中检索数据并将其添加到 tableView。在 tableView 的单元格中,我显示了当前数据库中的运动鞋数量。
我知道 .observeSingleEvent( .value)
和 .observe( .childAdded)
之间的区别。我需要实时更新,因为当数据在 tabA 中发送时,如果我切换到 tabB,我想在 tabA/ClassA 完成后看到新数据被添加到 tableView。
在 ClassB 中,我的观察者位于 viewWillAppear 中。我把它放在一个 pullDataFromFirebase()
函数中,每次视图出现函数 运行s。我还有 Notification observer 监听要在 tabA/ClassA 中发送的数据,以便它更新 tableView。通知事件 运行s pullDataFromFirebase()
再次
在 ClassA 中,在调用 Firebase 的回调中,我有通知 post 到 运行 ClassB 中的 pullDataFromFirebase()
函数.
我 运行 遇到的问题是,如果我在 tabB 中,而新数据正在更新,当它完成时,显示数据的单元格有一个计数,并且计数被丢弃.我调试了它,保存数据的 sneakerModels 数组有时会重复和三次重复新添加的数据。
例如,如果我在 Class B 并且数据库中有 2 双运动鞋,pullDataFromFirebase()
函数将 运行,tableView 单元格将显示 "You have 2 pairs of sneakers"
发生的事情是,如果我切换到 tabA/ClassA,然后添加了 1 双运动鞋,在更新时我切换到 tabB/ClassB,单元格仍然会显示 "You have 2 pairs of sneakers",但随后一旦它更新单元格会说 "You have 5 pairs of sneakers" 并且会出现 5 个单元格?如果我切换标签并返回,它会正确显示 "You have 3 pairs of sneakers" 和正确的单元格数量。
这就是通知出现的地方。一旦我添加了如果我经历相同的过程并从 2 款运动鞋开始,单元格会显示 "You have 2 pairs of sneakers",我转到 tabA,添加另一双,切换回tabB,仍然看到 "You have 2 pairs of sneakers"。发送数据后,单元格将短暂显示 "You have 5 pairs of sneakers" 并显示 5 个单元格,然后它会正确更新为 "You have 3 pairs of sneakers" 和正确数量的单元格(我不必切换选项卡)。
通知似乎有效,但有一个短暂的错误时刻。
我做了一些研究,我能找到的最多的是一些 post 说我需要使用信号量,但显然来自几个在下面留下评论的人,他们说信号量不应该被使用异步地。 我必须更新我的问题以排除信号量引用。
现在我在 pullDataFromFirebase() 的完成处理程序中 运行ning tableView.reloadData()。
完成后如何在观察者外部重新加载 tableView 以防止重复值?
型号:
class SneakerModel{
var sneakerName:String?
}
tabB/ClassB:
ClassB: UIViewController, UITableViewDataSource, UITableViewDelegate{
var sneakerModels[SneakerModel]
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(pullDataFromFirebase), name: NSNotification.Name(rawValue: "pullFirebaseData"), object: nil)
}
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
pullDataFromFirebase()
}
func pullDataFromFirebase(){
sneakerRef?.observe( .childAdded, with: {
(snapshot) in
if let dict = snapshot.value as? [String:Any]{
let sneakerName = dict["sneakerName"] as? String
let sneakerModel = SneakerModel()
sneakerModel.sneakerName = sneakerName
self.sneakerModels.append(sneakerModel)
//firebase runs on main queue
self.tableView.reloadData()
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sneakerModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SneakerCell", for: indexPath) as! SneakerCell
let name = sneakerModels[indePath.row]
//I do something else with the sneakerName and how pairs of each I have
cell.sneakerCount = "You have \(sneakerModels.count) pairs of sneakers"
return cell
}
}
}
tabA/ClassA:
ClassA : UIViewController{
@IBAction fileprivate func postTapped(_ sender: UIButton) {
dict = [String:Any]()
dict.updateValue("Adidas", forKey: "sneakerName")
sneakerRef.?.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
//1. show alert everything was successful
//2. post notification to ClassB to update tableView
NotificationCenter.default.post(name: Notification.Name(rawValue: "pullFirebaseData"), object: nil)
}
}
}
在我的应用程序的其他部分,我使用 filterDuplicates
方法,我将其作为 extension
添加到 Array
以过滤掉重复元素。我从 filter array duplicates:
得到的
extension Array {
func filterDuplicates(_ includeElement: @escaping (_ lhs:Element, _ rhs:Element) -> Bool) -> [Element]{
var results = [Element]()
forEach { (element) in
let existingElements = results.filter {
return includeElement(element, [=10=])
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
我找不到任何关于我的情况的特别之处,所以我使用了非常方便的 filterDuplicates 方法。
在我的原始代码中,我有一个日期 属性 我应该添加到问题中。我在这里添加它的任何方式,那个日期 属性 是我需要在 filterDuplicates 方法中使用来解决我的问题:
型号:
class SneakerModel{
var sneakerName:String?
var dateInSecs: NSNumber?
}
在 tabA/ClassA 中,无需在 Firebase 回调中使用通知,但将 dateInSecs 添加到字典中。
tabA/ClassA:
ClassA : UIViewController{
@IBAction fileprivate func postTapped(_ sender: UIButton) {
//you must add this or whichever date formatter your using
let dateInSecs:NSNumber? = Date().timeIntervalSince1970 as NSNumber?
dict = [String:Any]()
dict.updateValue("Adidas", forKey: "sneakerName")
dict.updateValue(dateInSecs!, forKey: "dateInSecs")//you must add this
sneakerRef.?.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
// 1. show alert everything was successful
// 2. no need to use the Notification so I removed it
}
}
}
并且在 tabB/ClassB Firebase 观察器的完成处理程序中的 pullDataFromFirebase()
函数中,我使用 filterDuplicates 方法过滤掉出现的重复元素。
tabB/ClassB:
func pullDataFromFirebase(){
sneakerRef?.observe( .childAdded, with: {
(snapshot) in
if let dict = snapshot.value as? [String:Any]{
let sneakerName = dict["sneakerName"] as? String
let sneakerModel = SneakerModel()
sneakerModel.sneakerName = sneakerName
self.sneakerModels.append(sneakerModel)
// use the filterDuplicates method here
self.sneakerModels = self.sneakerModels.filterDuplicates{[=13=].dateInSecs == .dateInSecs}
self.tableView.reloadData()
}
})
}
基本上,filterDuplicates 方法循环遍历 sneakerModels 数组,将每个元素与 dateInSecs 进行比较,并在找到它们时排除副本。然后我用结果重新初始化 sneakerModels,一切都很好。
另请注意,ClassB 的 viewDidLoad 中不需要通知观察器,因此我将其删除。
我有一个带有 2 个选项卡的 tabBar 控制器:包含 ClassA 的 tabA 和包含 ClassB 的 tabB。我在 tabA/ClassA 中将数据发送到 Firebase 数据库,并在 tabB/ClassB 中观察数据库,我在其中检索数据并将其添加到 tableView。在 tableView 的单元格中,我显示了当前数据库中的运动鞋数量。
我知道 .observeSingleEvent( .value)
和 .observe( .childAdded)
之间的区别。我需要实时更新,因为当数据在 tabA 中发送时,如果我切换到 tabB,我想在 tabA/ClassA 完成后看到新数据被添加到 tableView。
在 ClassB 中,我的观察者位于 viewWillAppear 中。我把它放在一个 pullDataFromFirebase()
函数中,每次视图出现函数 运行s。我还有 Notification observer 监听要在 tabA/ClassA 中发送的数据,以便它更新 tableView。通知事件 运行s pullDataFromFirebase()
再次
在 ClassA 中,在调用 Firebase 的回调中,我有通知 post 到 运行 ClassB 中的 pullDataFromFirebase()
函数.
我 运行 遇到的问题是,如果我在 tabB 中,而新数据正在更新,当它完成时,显示数据的单元格有一个计数,并且计数被丢弃.我调试了它,保存数据的 sneakerModels 数组有时会重复和三次重复新添加的数据。
例如,如果我在 Class B 并且数据库中有 2 双运动鞋,pullDataFromFirebase()
函数将 运行,tableView 单元格将显示 "You have 2 pairs of sneakers"
发生的事情是,如果我切换到 tabA/ClassA,然后添加了 1 双运动鞋,在更新时我切换到 tabB/ClassB,单元格仍然会显示 "You have 2 pairs of sneakers",但随后一旦它更新单元格会说 "You have 5 pairs of sneakers" 并且会出现 5 个单元格?如果我切换标签并返回,它会正确显示 "You have 3 pairs of sneakers" 和正确的单元格数量。
这就是通知出现的地方。一旦我添加了如果我经历相同的过程并从 2 款运动鞋开始,单元格会显示 "You have 2 pairs of sneakers",我转到 tabA,添加另一双,切换回tabB,仍然看到 "You have 2 pairs of sneakers"。发送数据后,单元格将短暂显示 "You have 5 pairs of sneakers" 并显示 5 个单元格,然后它会正确更新为 "You have 3 pairs of sneakers" 和正确数量的单元格(我不必切换选项卡)。
通知似乎有效,但有一个短暂的错误时刻。
我做了一些研究,我能找到的最多的是一些 post 说我需要使用信号量,但显然来自几个在下面留下评论的人,他们说信号量不应该被使用异步地。 我必须更新我的问题以排除信号量引用。
现在我在 pullDataFromFirebase() 的完成处理程序中 运行ning tableView.reloadData()。
完成后如何在观察者外部重新加载 tableView 以防止重复值?
型号:
class SneakerModel{
var sneakerName:String?
}
tabB/ClassB:
ClassB: UIViewController, UITableViewDataSource, UITableViewDelegate{
var sneakerModels[SneakerModel]
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(pullDataFromFirebase), name: NSNotification.Name(rawValue: "pullFirebaseData"), object: nil)
}
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
pullDataFromFirebase()
}
func pullDataFromFirebase(){
sneakerRef?.observe( .childAdded, with: {
(snapshot) in
if let dict = snapshot.value as? [String:Any]{
let sneakerName = dict["sneakerName"] as? String
let sneakerModel = SneakerModel()
sneakerModel.sneakerName = sneakerName
self.sneakerModels.append(sneakerModel)
//firebase runs on main queue
self.tableView.reloadData()
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sneakerModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SneakerCell", for: indexPath) as! SneakerCell
let name = sneakerModels[indePath.row]
//I do something else with the sneakerName and how pairs of each I have
cell.sneakerCount = "You have \(sneakerModels.count) pairs of sneakers"
return cell
}
}
}
tabA/ClassA:
ClassA : UIViewController{
@IBAction fileprivate func postTapped(_ sender: UIButton) {
dict = [String:Any]()
dict.updateValue("Adidas", forKey: "sneakerName")
sneakerRef.?.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
//1. show alert everything was successful
//2. post notification to ClassB to update tableView
NotificationCenter.default.post(name: Notification.Name(rawValue: "pullFirebaseData"), object: nil)
}
}
}
在我的应用程序的其他部分,我使用 filterDuplicates
方法,我将其作为 extension
添加到 Array
以过滤掉重复元素。我从 filter array duplicates:
extension Array {
func filterDuplicates(_ includeElement: @escaping (_ lhs:Element, _ rhs:Element) -> Bool) -> [Element]{
var results = [Element]()
forEach { (element) in
let existingElements = results.filter {
return includeElement(element, [=10=])
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
我找不到任何关于我的情况的特别之处,所以我使用了非常方便的 filterDuplicates 方法。
在我的原始代码中,我有一个日期 属性 我应该添加到问题中。我在这里添加它的任何方式,那个日期 属性 是我需要在 filterDuplicates 方法中使用来解决我的问题:
型号:
class SneakerModel{
var sneakerName:String?
var dateInSecs: NSNumber?
}
在 tabA/ClassA 中,无需在 Firebase 回调中使用通知,但将 dateInSecs 添加到字典中。
tabA/ClassA:
ClassA : UIViewController{
@IBAction fileprivate func postTapped(_ sender: UIButton) {
//you must add this or whichever date formatter your using
let dateInSecs:NSNumber? = Date().timeIntervalSince1970 as NSNumber?
dict = [String:Any]()
dict.updateValue("Adidas", forKey: "sneakerName")
dict.updateValue(dateInSecs!, forKey: "dateInSecs")//you must add this
sneakerRef.?.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
// 1. show alert everything was successful
// 2. no need to use the Notification so I removed it
}
}
}
并且在 tabB/ClassB Firebase 观察器的完成处理程序中的 pullDataFromFirebase()
函数中,我使用 filterDuplicates 方法过滤掉出现的重复元素。
tabB/ClassB:
func pullDataFromFirebase(){
sneakerRef?.observe( .childAdded, with: {
(snapshot) in
if let dict = snapshot.value as? [String:Any]{
let sneakerName = dict["sneakerName"] as? String
let sneakerModel = SneakerModel()
sneakerModel.sneakerName = sneakerName
self.sneakerModels.append(sneakerModel)
// use the filterDuplicates method here
self.sneakerModels = self.sneakerModels.filterDuplicates{[=13=].dateInSecs == .dateInSecs}
self.tableView.reloadData()
}
})
}
基本上,filterDuplicates 方法循环遍历 sneakerModels 数组,将每个元素与 dateInSecs 进行比较,并在找到它们时排除副本。然后我用结果重新初始化 sneakerModels,一切都很好。
另请注意,ClassB 的 viewDidLoad 中不需要通知观察器,因此我将其删除。