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

これは、observe オプションを使用しているためです。これはおそらくあなたに数回通知しています。クラッシュは、前に 'enter' を呼び出して 'leave' を呼び出したために発生します。つまり、「enter」と呼んだということです。そして、あなたは「去る」と呼びます。しかし、完了を観察したため、おそらく複数回呼び出されます。「enter」を一度だけ呼び出したときに、別の「leave」呼び出しをトリガーします。

このコードでクラッシュを簡単に再現できます

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).

監視機能が必要かどうかはわかりません。つまり、オブジェクトの変更をリッスンします。

一般的に、Firebase による新しい (それほど新しいものではない) DB である Firestore を使用することをお勧めします。または、このガイドに従って、Firebase Realtime Database からデータを取得/設定しますhttps://firebase.google.com/docs/database/ios/read-and-write

「リスニング」、つまり観察機能が必要な場合、DispatchGroup の使用が実装にどのように役立つかわかりません。一般に、たとえば、2 つ (またはそれ以上) の API 呼び出しを並行してリリースし、それらからすべての情報を収集する場合に使用します。DispatchfchGroup を作成し、リリースしているコール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 に答える