0

我创建了一种从 Firebase 获取用户消息的方法,但是当离开DispatchGroup应用程序崩溃时会导致此错误Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

我不确定我做错了什么。请帮助和解释我。

代码:

public func fetchMessages(for userId: String, completion: @escaping (_ result: Result<([Message], [String: Message]), Error>) -> Void) {
        
        let group = DispatchGroup()
        
        var messages = [Message]()
        var messagesDict = [String: Message]()
        
        group.enter()
        database.child("user-messages").child(userId).observe(.childAdded, with: { [weak self] snapshot in
            
            let messageId = snapshot.key
            let messagesRef = self?.database.child("messages").child(messageId)
            
            messagesRef?.observeSingleEvent(of: .value, with: { snapshot in
                
                if let dict = snapshot.value as? [String: AnyObject] {
                    
                    let message = Message(dict: dict)
                    
                    if let chatPartnerId = message.chatPartnerId() {
                        
                        messagesDict[chatPartnerId] = message
                        messages = Array(messagesDict.values)
                        
                        messages.sort { message1, message2 in
                            guard let timestamp1 = message1.timestamp?.intValue, let timestamp2 = message2.timestamp?.intValue else { return false }
                            return timestamp1 > timestamp2
                        }
                        
                        group.leave() // Crashes
                    }
                }
                
            }, withCancel: nil)
            
        }, withCancel: nil)
        
        group.notify(queue: .main) {
            print("Array: \(messages)\nDict: \(messagesDict)")
        }
    }
4

1 回答 1

1

这是因为您正在使用观察选项。这可能会多次通知您。崩溃的发生是因为您之前调用了 'leave' 并调用了 'enter'。我的意思是你确实叫'输入'。你确实叫'离开'。但是因为你观察到完成可能不止一次被调用。当您只调用一次“进入”时,这将触发另一个“离开”呼叫。

您可以使用此代码轻松重现崩溃

import Foundation

let group = DispatchGroup()

group.enter()

group.notify(queue: .main) {
    print("hello")
}

group.leave()
group.leave() // error: Execution was interrupted, reason: EXC_BREAKPOINT (code=1, subcode=0x18013d990).

我不确定您是否需要观察功能——即监听对象的变化。

一般来说,我建议使用 Firestore - Firebase 的新(不是那个新)数据库。或按照本指南从 Firebase 实时数据库获取/设置数据https://firebase.google.com/docs/database/ios/read-and-write

如果您需要“聆听”,即观察功能,我不确定 DispatchGroup 的使用如何帮助您实现。例如,当您并行发布 2 个(或更多)API 调用并希望从中收集所有信息时,您通常会使用它。您将创建一个 DispatfchGroup,enter根据您发布的调用次数进行调用,并leave在收集相关信息后调用。

像这样的东西

struct AppInfo {
  var items: [items] = []
  var instructors: [Instructors] = []
  var students: [Student] = []
}

func appBootstrapAPICalls(completion: ((AppInfo) -> Void)?) {
  var appInfo = AppIfno()
  let group = DispatchGroup()
  group.enter()
  group.enter()
  group.enter()

  self.fetchItems { items in
    appInfo.items.append(contentsOf: items)
    group.leave()
  }

  self.fetchStudents { students in
    appInfo.students.append(contentsOf: students)
    group.leave()
  }

  self.fetchInstructors { instructors in
    appInfo.instructors.append(contentsOf: instructors)
    group.leave()
  }
  
  group.notify(queue: .main) {
    completion?(appInfo)
  }
}
于 2022-02-25T04:31:33.627 回答