为啥这个函数每次运行时都会将对象两次附加到数组中?

Posted

技术标签:

【中文标题】为啥这个函数每次运行时都会将对象两次附加到数组中?【英文标题】:Why does this function append the object twice to the array each time it runs?为什么这个函数每次运行时都会将对象两次附加到数组中? 【发布时间】:2021-03-18 02:57:32 【问题描述】:

我正在使用 swift 的 DispatchGroup() 来帮助编排一个 for 循环

在 firesbase 中找到文档 将文档转换为自定义对象 将自定义对象附加到数组中

每次传递时,函数最终都会将每个对象两次附加到数组中,我不明白为什么。 这是函数...

    func getFriends() 
    
    // Initialize the DispatchGroup
    let group = DispatchGroup()

    // the myFriends array contains documentIDs that I am using to fetch documents from firebase
    //
    for pid in myFriendObj.myFriends 
        group.enter()
        
        _ = Firestore.firestore().collection("Players")
            .whereField(FieldPath.documentID(), isEqualTo:  pid)
            .addSnapshotListener  [self] querySnapshot, error in

                if let error = error 
                    print("Error getting > Players: \(error.localizedDescription)")
                    return
                
                guard let querySnapshot = querySnapshot else  return 

                self.players.append(
                    contentsOf: querySnapshot.documents.compactMap  document in
                    try? document.data(as: UserProfile.self)
                )
           
                group.leave()
                
         
    
    
    group.notify(queue: DispatchQueue.global(qos: .background)) 
        // I'm currently eliminating the dups via this fancy extends method.
        self.players = self.players.removeDuplicates()
    
    

:: 更新 ::

在这方面仍然没有运气 - 我什至删除了 dispatchgroup 和 snapshotlistener 回调,并且当类的实例被实例化时,这段代码仍然调用 get() 两次。这是新的、更简单的代码...

class FriendRepository: ObservableObject 

private    let store = Firestore.firestore()
private    let friendPath: String = "MyFriends"
@Published var friendIDs: [String] = []

var userId = ""

private let authenticationService = AuthenticationService()
private var cancellables: Set<AnyCancellable> = []


init() 
    authenticationService.$user
        .compactMap  user in
            user?.uid
        
        .assign(to: \.userId, on: self)
        .store(in: &cancellables)

    authenticationService.$user
        .receive(on: DispatchQueue.main)
        .sink  [weak self] _ in
            self?.get()
        
        .store(in: &cancellables)



 

func get( ) 
    store.collection(friendPath).document(userId).getDocument (document, error) in
        let result = Result 
          try document?.data(as: Friends.self)
        
        switch result 
        case .success(let f):
            if let f = f 
                print("friends:>> \(f.myFriends)")
                self.friendIDs = f.myFriends
             else 
                print("Document does not exist")
            
        case .failure(let error):
            print("Error decoding city: \(error)")
        
    

当一个新实例运行 init() 时,我在控制台中看到了这个...它打印了 friends:>> 语句两次

friends:>> ["PHyUe6mAc3LodM5guJJU"]
friends:>> ["PHyUe6mAc3LodM5guJJU"]

【问题讨论】:

【参考方案1】:

每次数据库中发生更改时,您的 addSnapshotListener 闭包都会被调用,其中包含与查询匹配的所有数据 - 即使该数据自上次调用以来没有更改。这通常意味着您需要在回调顶部清空 self.players,或者循环遍历 documentChanges 集合以确定更改的确切内容。

【讨论】:

谢谢你,弗兰克!所以我一直在修补清除 self.players 但不确定在哪里执行 removeAll() 语句。您提到“在回调的顶部”,但我不确定我正在使用回调。你能指出在哪里放置这条线吗? 闭包/回调是您传递给函数调用的代码块,然后在某个时刻被该函数调用。这里:.addSnapshotListener [self] querySnapshot, error in里面的代码块是一个回调/闭包,你可以清除if let error = error 上面的列表。 弗兰克,运气不好。我已经大大简化了事情并删除了回调以及调度组,我什至只读取了一个 Firestore 文档,并且在类实例启动时它仍然进行了两次读取。查看新代码:: UPDATED :: 嗯...在那种情况下,我不确定可能是什么问题。我希望有更好的 Swift/SwiftUI 技能的人能看到发生了什么。【参考方案2】:
    func getFriends() 
// this will empty the players array when ever the get friends function gets called. 
self.players.removeAll()
// Initialize the DispatchGroup
let group = DispatchGroup()

// the myFriends array contains documentIDs that I am using to fetch documents from firebase
//
for pid in myFriendObj.myFriends 
    group.enter()
    
    _ = Firestore.firestore().collection("Players")
        .whereField(FieldPath.documentID(), isEqualTo:  pid)
        .addSnapshotListener  [self] querySnapshot, error in

            if let error = error 
                print("Error getting > Players: \(error.localizedDescription)")
                return
            
            guard let querySnapshot = querySnapshot else  return 

            self.players.append(
                contentsOf: querySnapshot.documents.compactMap  document in
                try? document.data(as: UserProfile.self)
            )
       
            group.leave()
   
     

【讨论】:

players.removeAll() 请添加一些代码示例或文档链接以获得更好的答案:)

以上是关于为啥这个函数每次运行时都会将对象两次附加到数组中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥,每次打开EXcel都会这个窗口,所以导致每次都要开两次才行!

Angular2,为啥每次移动鼠标时都会调用函数

引用计数器和析构函数被调用两次

C++ 问题我每次运行程序时都会得到“nan”作为输出

为啥我的函数每次调用时都会创建一个新对象?

为啥eclipselink每次重新启动时都会消耗整个allocationSize?