在Cloud Firestore(Swift)中运行collectionGroup查询时崩溃

时间:2020-10-21 07:51:55

标签: ios swift firebase google-cloud-firestore

我使用Swift,SwiftUI和Cloud Firestore运行了一个移动应用程序项目,我需要根据他们的不同设置/偏好来查找用户。我已经通过使用collectionGroup查询解决了这一问题。但是有时(可能是十分之一)查询会崩溃,而没有任何(对我而言)可理解的错误消息。组合索引是使用XCode提供的http链接创建的。

这是我使用的功能:

func getUsersFromActivityPrefs(genders:[String], activities:[Int],skillScore_min:Int, skillScore_max:Int,completion:@escaping ([String]) -> ()) {
   
var matchUsers = [String]()
var count = 0
let db = Firestore.firestore()

for gender in genders {
    for activity in activities {
        let dbRef = db.collectionGroup("activity_preferences")
            .whereField("gender", isEqualTo: gender)
            .whereField("activityid", isEqualTo: activity)
            .whereField("status", isEqualTo: true)
            .whereField("skill_score", isGreaterThanOrEqualTo: skillScore_min)
            .whereField("skill_score", isLessThanOrEqualTo: skillScore_max)
            .limit(to: 100)
        dbRef.getDocuments {( snap, err) in
            count+=1
            if err != nil {
                print(err!.localizedDescription)
            }
            for i in snap!.documentChanges{
                let uid = i.document.get("uid") as? String ?? ""
                if uid != "" && !matchUsers.contains(uid) {
                    matchUsers.append(uid)
                    if matchUsers.count == 100 {
                        count = genders.count * activities.count
                        completion(matchUsers) //escaping completion handler
                        return
                    }
                }
            }
            if count == genders.count * activities.count {
                completion(matchUsers)
                return
            }
        }
    }
}

}

我已经附上了XCode的跟踪日志和崩溃消息。我正在使用最新版本的Firebase SDK,部署目标是iOS14。 这是我得到的跟踪日志:

线程#1,队列='com.apple.main-thread',停止原因= EXC_BAD_ACCESS(代码= 1,地址= 0x4f) 帧#0:0x00007fff4b80dd66 AttributeGraph AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, bool*, long) + 322 frame #1: 0x00007fff4b81f1a5 AttributeGraph AGGraphGetValue + 203 框架2:0x00007fff55e7ffab SwiftUI SwiftUI.DynamicBody.phase.getter : SwiftUI._GraphInputs.Phase + 27 frame #3: 0x00007fff55e80176 SwiftUI SwiftUI.DynamicBody.updateValue()->()+ 294 框架#4:0x00007fff55b9583a SwiftUI partial apply forwarder for implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (A1.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<A1>) -> AttributeGraph.Attribute<A> in AttributeGraph.Attribute.init<A where A == A1.Value, A1: AttributeGraph.StatefulRule>(A1) -> AttributeGraph.Attribute<A> + 26 frame #5: 0x00007fff4b808d03 AttributeGraph AG :: Graph :: UpdateStack :: update()+ 505 框架6:0x00007fff4b809199 AttributeGraph AG::Graph::update_attribute(AG::data::ptr<AG::Node>, bool) + 335 frame #7: 0x00007fff4b80d8e8 AttributeGraph AG :: Graph :: value_ref(AG :: AttributeID,AGSwiftMetadata const *,bool *)+ 130 框架#8:0x00007fff4b81f1f3 AttributeGraph AGGraphGetValue + 281 frame #9: 0x00007fff561aeeb7 SwiftUI SwiftUI.GraphHost.updatePreferences()-> Swift.Bool + 39 框架#10:0x00007fff55c9a8cf SwiftUI SwiftUI.ViewGraph.updateOutputs(at: SwiftUI.Time) -> () + 95 frame #11: 0x00007fff5611310c SwiftUI封闭#1()->()in(在SwiftUI中的扩展名):SwiftUI.ViewRendererHost.render(时间间隔:Swift.Double,updateDisplayList:Swift.Bool)->()+ 1308 框架#12:0x00007fff56112327 SwiftUI (extension in SwiftUI):SwiftUI.ViewRendererHost.render(interval: Swift.Double, updateDisplayList: Swift.Bool) -> () + 343 frame #13: 0x00007fff55ba07de SwiftUI关闭#1()->()在SwiftUI._UIHostingView.requestImmediateUpdate()->()+ 62 框架#14:0x00007fff562739ae SwiftUI reabstraction thunk helper from @escaping @callee_guaranteed () -> () to @escaping @callee_unowned @convention(block) () -> () + 14 frame #15: 0x0000000112ebd8ac libdispatch.dylib _ dispatch_call_block_and_release + 12 框架16:0x0000000112ebea88 libdispatch.dylib _dispatch_client_callout + 8 frame #17: 0x0000000112eccf23 libdispatch.dylib _ dispatch_main_queue_callback_4CF + 1152 框架#18:0x00007fff203a8276 CoreFoundation __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9 frame #19: 0x00007fff203a2b06 CoreFoundation __ CFRunLoopRun + 2685 框架#20:0x00007fff203a1b9e CoreFoundation CFRunLoopRunSpecific + 567 frame #21: 0x00007fff2b773db3 GraphicsServices GSEventRunModal + 139 框架#22:0x00007fff24660af3 UIKitCore -[UIApplication _run] + 912 frame #23: 0x00007fff24665a04 UIKitCore UIApplicationMain + 101 帧#24:0x000000010db84a5b陪练main at AppDelegate.swift:14:7 frame #25: 0x00007fff20257415 libdyld.dylib开始+ 1

附件: XCode 1中崩溃 综合索引2

1 个答案:

答案 0 :(得分:0)

func getUsersFromActivityPrefs(genders: [String], activities: [Int], skillScore_min: Int, skillScore_max: Int, completion: @escaping ([String]) -> Void) {
    var matchUsers = [String]()
    var count = 0
    let db = Firestore.firestore()
    let dispatch = DispatchGroup() // instantiate dispatch group outside loop
    
    for gender in genders {
        for activity in activities {
            dispatch.enter() // enter group on each iteration
            
            let dbRef = db.collectionGroup("activity_preferences")
                .whereField("gender", isEqualTo: gender)
                .whereField("activityid", isEqualTo: activity)
                .whereField("status", isEqualTo: true)
                .whereField("skill_score", isGreaterThanOrEqualTo: skillScore_min)
                .whereField("skill_score", isLessThanOrEqualTo: skillScore_max)
                .limit(to: 100)
            
            dbRef.getDocuments {( snap, err) in
                if let snap = snap {
                    count += 1
                    
                    for doc in snap.documents {
                        if let uid = doc.get("uid") as? String,
                           !matchUsers.contains(uid) {
                            matchUsers.append(uid)
                        }
                    }
                } else if let err = err {
                    print(err)
                }
                
                dispatch.leave() // always leave no matter what the db returned
            }
        }
    }
    
    /*
     this is the group's completion handler and it's only
     called once after all groups have entered and left
     */
    dispatch.notify(queue: .main) {
        completion(matchUsers)
    }
}