gpt4 book ai didi

ios - 我的 native 应用程序在Swift中编译器生成的崩溃

转载 作者:行者123 更新时间:2023-12-01 19:34:04 26 4
gpt4 key购买 nike

我的healthkit快速代码一直在生产环境中崩溃,我无法终生解决。我对Swift相当陌生,所以也许我在实现过程中犯了一个根本性的错误。

崩溃的特征:

  • 似乎仅在生产中发生。 (我们的内部测试程序仅包含10个设备(因此,巧合的是它没有在那里被拾取)。
  • 在iOS版本中发生-10,11,12,13
  • 仅出现在很小的一组用户(占活跃观众的1.5%)中,但对于这些相同的用户却非常常见。

  • 请从下面的我的Crashlytics帐户中找到崩溃日志。
    Crashed: com.facebook.react.HKManagerQueue
    0 stepapp 0x100f4f324 specialized HKManager.getTotal(_:typeStr:unit:options:completion:) + 4372984612 (<compiler-generated>:4372984612)
    1 stepapp 0x100f52e04 HKManager._getTotals(_:completion:) + 397 (HKManager.swift:397)
    2 stepapp 0x100f532ac @objc HKManager.getTotals(_:resolver:rejecter:) + 4373000876 (<compiler-generated>:4373000876)
    3 CoreFoundation 0x1af698c20 __invoking___ + 144
    4 CoreFoundation 0x1af568d30 -[NSInvocation invoke] + 300
    5 CoreFoundation 0x1af569908 -[NSInvocation invokeWithTarget:] + 76
    6 stepapp 0x101184e6c -[RCTModuleMethod invokeWithBridge:module:arguments:] + 241556
    7 stepapp 0x101187248 facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&) + 250736
    8 stepapp 0x101186fac invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int) + 250068
    9 libdispatch.dylib 0x1af35e610 _dispatch_call_block_and_release + 24
    10 libdispatch.dylib 0x1af35f184 _dispatch_client_callout + 16
    11 libdispatch.dylib 0x1af30b404 _dispatch_lane_serial_drain$VARIANT$mp + 608
    12 libdispatch.dylib 0x1af30bdf8 _dispatch_lane_invoke$VARIANT$mp + 420
    13 libdispatch.dylib 0x1af315314 _dispatch_workloop_worker_thread + 588
    14 libsystem_pthread.dylib 0x1af3aeb88 _pthread_wqthread + 276
    15 libsystem_pthread.dylib 0x1af3b1760 start_wqthread + 8
    com.apple.main-thread
    0 libsystem_kernel.dylib 0x19c960634 mach_msg_trap + 8
    1 libsystem_kernel.dylib 0x19c95faa0 mach_msg + 72
    2 CoreFoundation 0x19cb08288 __CFRunLoopServiceMachPort + 216
    3 CoreFoundation 0x19cb033a8 __CFRunLoopRun + 1444
    4 CoreFoundation 0x19cb02adc CFRunLoopRunSpecific + 464
    5 GraphicsServices 0x1a6aa3328 GSEventRunModal + 104
    6 UIKitCore 0x1a0c1063c UIApplicationMain + 1936
    7 stepapp 0x100edf330 main + 14 (main.m:14)
    8 libdyld.dylib 0x19c98c360 start + 4
    com.apple.uikit.eventfetch-thread
    0 libsystem_kernel.dylib 0x19c960634 mach_msg_trap + 8
    1 libsystem_kernel.dylib 0x19c95faa0 mach_msg + 72
    2 CoreFoundation 0x19cb08288 __CFRunLoopServiceMachPort + 216
    3 CoreFoundation 0x19cb033a8 __CFRunLoopRun + 1444
    4 CoreFoundation 0x19cb02adc CFRunLoopRunSpecific + 464
    5 Foundation 0x19ce42784 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 228
    6 Foundation 0x19ce42664 -[NSRunLoop(NSRunLoop) runUntilDate:] + 88
    7 UIKitCore 0x1a0ca8e80 -[UIEventFetcher threadMain] + 152
    8 Foundation 0x19cf7309c __NSThread__start__ + 848
    9 libsystem_pthread.dylib 0x19c8a5d8c _pthread_start + 156
    10 libsystem_pthread.dylib 0x19c8a976c thread_start + 8

    我在下面附加了我的实现,其中包含崩溃日志中提到的行
    func _getTotals(_ options: Dictionary<String, Any>, completion: @escaping (Dictionary<String, Double>?) -> Void) {
    var stepsDone = false;
    var distanceDone = false;
    var caloriesDone = false;

    let steps = HKQuantityType.quantityType(forIdentifier: .stepCount);
    let distance = HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning);
    let calories = HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned);

    var results = Dictionary<String, Double>();

    // 👇 THIS IS LINE 397 which is indicated in the crash report above
    self.getTotal(steps!, typeStr: HKManager.STEP_TYPE_STR, unit: HKUnit.count(), options: options) { (totalSteps, error) in
    stepsDone = true;
    if (totalSteps != nil) {
    results["steps"] = totalSteps;
    }

    if (stepsDone == true && distanceDone == true && caloriesDone == true) {
    return completion(results);
    }
    }

    self.getTotal(distance!, typeStr: HKManager.DISTANCE_TYPE_STR, unit: HKUnit.meter(), options: options) { (totalDistance, error) in
    distanceDone = true;
    if (totalDistance != nil) {
    results["distance"] = totalDistance;
    }
    if (stepsDone == true && distanceDone == true && caloriesDone == true) {
    return completion(results);
    }
    }

    self.getTotal(calories!, typeStr: HKManager.CALORIES_TYPE_STR, unit: HKUnit.kilocalorie(), options: options) { (totalCalories, error) in
    caloriesDone = true;
    if (totalCalories != nil) {
    results["calories"] = totalCalories;
    }
    if (stepsDone == true && distanceDone == true && caloriesDone == true) {
    return completion(results);
    }
    }
    }

    我还附加了上述代码中使用的self.getTotal(...)函数的实现。需要指出的是,在此功能中,我切换到在后台环境中执行我的HealthKit查询,以确保这些查询不在主线程上运行。我认为这可能是导致车祸的原因。

    func getTotal(_ type: HKQuantityType, typeStr: String, unit: HKUnit, options: Dictionary<String, Any>, completion: @escaping (Double?, Error?) -> Void) {
    guard (self.healthStore != nil) else {
    let error = NSError(domain: "Healthkit not initialized", code: 50, userInfo: [:]);
    return completion(nil, error);
    }

    var start: Date;

    if (options["startDate"] != nil) {
    start = self.strToDate(dateStr: options["startDate"] as! String);
    } else {
    let date = Date()
    let cal = Calendar(identifier: .gregorian)
    let midnight = cal.startOfDay(for: date);

    start = midnight;
    }

    var ignoreMin = false;
    if (options["ignoreMin"] != nil) {
    ignoreMin = options["ignoreMin"] as! Bool;
    }

    if (ignoreMin != true && start < self.minStartDate && self.minStartDate != nil) {
    start = self.minStartDate;
    }

    var end: Date = Date();
    if (options["endDate"] != nil) {
    end = self.strToDate(dateStr: options["endDate"] as! String);
    }

    var sources = options["sources"] as? [String];
    if (sources == nil || (sources?.capacity)! < 1) {
    sources = ["com.apple.health."];
    }

    DispatchQueue.global(qos: .background).async { [weak self] in

    // fetch sources
    self?.getSources(sampleTypeStr: typeStr, sampleType: type, sources: sources!) { (s, error) in

    if (s == nil || ((s?.capacity) ?? 0) < 1) {
    return completion(0.0, nil);
    }

    let sourcePredicate = HKQuery.predicateForObjects(from: s!);

    // todo: enter date patterns
    let datePredicate = HKQuery.predicateForSamples(withStart: start, end: end, options: []);

    // predicate = [NSPredicate predicateWithFormat:@"metadata.%K != YES", HKMetadataKeyWasUserEntered];
    let manualPredicate = HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyWasUserEntered, operatorType: .notEqualTo, value: "YES");

    let compound = NSCompoundPredicate(andPredicateWithSubpredicates: [
    sourcePredicate,
    datePredicate,
    manualPredicate
    ]);


    let statOptions = HKStatisticsOptions.cumulativeSum;


    let query = HKStatisticsQuery.init(quantityType:type , quantitySamplePredicate: compound, options: statOptions, completionHandler: { (query, results, error) in

    if (error != nil) {
    return completion(nil, error);
    }

    var total = 0.0;

    // handle if results came back as nil, or sum came back as nil
    guard (results != nil && results?.sumQuantity() != nil) else {
    return completion(total, nil);
    }

    total = results?.sumQuantity()?.doubleValue(for: unit) ?? 0.0;

    return completion(total, nil);
    });

    // execute stats query for step counts by source
    self?.healthStore?.execute(query);
    }
    }
    }

    我将非常感谢任何形式的帮助或指示。提前致谢。

    最佳答案

    明显的问题是从多个线程并行写入字典对象。用伪代码:

    results = [:]
    getTotal() // start thread 1
    getTotal() // start thread 2
    getTotal() // start thread 3

    thread 1: write results
    thread 2: write results
    thread 3: write results

    Swift Dictionary不是线程安全的,必须同步并行写入。

    在您的代码中,简单的更改就是将 DispatchQueue异步上移到 _getTotals,然后从 DispatchQueue中删除 getTotal:

    func _getTotals(_ options: Dictionary<String, Any>, completion: @escaping (Dictionary<String, Double>?) -> Void) {
    DispatchQueue.global(qos: .background).async {
    var results = Dictionary<String, Double>()
    self.getTotal(...)
    self.getTotal(...)
    self.getTotal(...)
    }
    }

    这样,所有内容都在单个后台线程中运行; getTotal调用被依次依次调用。

    但是,如果需要并行运行 getTotal,则必须同步对 results变量的访问。通常,这是通过使用预定义的共享串行队列再次调用 DispatchQueue async来完成的。

    关于ios - 我的 native 应用程序在Swift中编译器生成的崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60788333/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com