我有一个带有2个标签的tabBar控制器:tabA包含ClassA,tabB包含ClassB。我在tabA / ClassA中将数据发送到Firebase数据库,然后在tabB / ClassB中观察数据库,在那里我检索它并将其添加到tableView。在tableView的单元格中,我显示了数据库中当前的运动鞋数量。
我知道.observeSingleEvent( .value)
与.observe( .childAdded)
之间的区别。我需要实时更新,因为当数据在tabA中发送时,如果我切换到tabB,我想在tabA / ClassA完成后看到新数据被添加到tableView。
在ClassB中,我在viewWillAppear中有我的观察者。我把它放在pullDataFromFirebase()
函数中,每次出现视图时函数都会运行。我还有Notification观察器,它监听要在tabA / ClassA中发送的数据,以便它更新tableView。通知事件再次运行pullDataFromFirebase()
在ClassA中,在对Firebase的调用回调中,我有Notification帖子在ClassB中运行pullDataFromFirebase()
函数。
我遇到的问题是,当新数据正在更新时我是否在tabB中,当它完成时,显示数据的单元格有一个计数并且计数被丢弃。我对它进行了调试,并且保存数据的sneakerModels数组有时会重复复制并使新添加的数据重复三次。
例如,如果我在B级并且数据库中有2对运动鞋,pullDataFromFirebase()
func将运行,而tableView单元格将显示“你有2双运动鞋”
发生的事情是,如果我切换到tabA / ClassA,然后添加了一双运动鞋,当它更新时我切换到tabB / ClassB,单元格仍然会说“你有2双运动鞋”但是一旦更新细胞会说“你有5双运动鞋”,会出现5个细胞?如果我切换标签然后回来,它会正确显示“你有3双运动鞋”和正确数量的单元格。
这就是通知的来源。一旦我补充说,如果我经历了相同的过程,并开始使用2个运动鞋,单元格会说“你有2双运动鞋”,我去tabA,添加另一对,切换回来到tabB仍然看到“你有2双运动鞋”。一旦数据被发送,细胞将简要显示“你有5对运动鞋”并显示5个细胞,然后它将正确更新为“你有3对运动鞋”和正确数量的细胞(我没有必要切换标签)。
通知似乎有效,但有一个短暂不正确的时刻。
我做了一些研究,我发现的最多的是一些帖子,说我需要使用信号量,但显然来自几位留下评论的人,他们说信号量并不意味着异步使用。 我不得不更新我的问题以排除信号量参考。
现在我正在pullDataFromFirebase()的完成处理程序中运行tableView.reloadData()。
如果在完成后将tableView重新加载到观察者之外以防止重复值?
型号:
class SneakerModel{
var sneakerName:String?
}
塔布/ 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
}
}
}
塔巴/ 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)
}
}
}
答案 0 :(得分:0)
在我的应用的其他部分,我使用def func():
a = 4
print(a)
# this prints nothing unless you call func()
方法作为filterDuplicates
添加到extension
来过滤掉重复的元素。我是从filter array duplicates得到的:
Array
我无法在我的情况下找到任何特别的东西所以我使用了filterDuplicates方法非常方便。
在我的原始代码中,我有一个日期属性,我应该将其添加到问题中。我在这里添加它的任何方式和date属性是我需要在filterDuplicates方法中使用来解决我的问题:
型号:
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, $0)
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
在tabA / ClassA内部,无需使用Firebase回调中的Notification,但是将dateInSecs添加到dict。
塔巴/ ClassA的:
class SneakerModel{
var sneakerName:String?
var dateInSecs: NSNumber?
}
在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
}
}
}
函数中Firebase观察者的完成处理程序内的tabB / ClassB中,我使用了filterDuplicates方法来过滤掉显示的重复元素。
塔布/ ClassB的:
pullDataFromFirebase()
基本上,filterDuplicates方法循环遍历sneakerModels数组,将每个元素与dateInSecs进行比较,当它找到它们时,它会排除副本。然后我用结果重新初始化sneakerModels,一切都很顺利。
另请注意,ClassB的viewDidLoad中没有任何Notification观察者的需要,所以我将其删除了。