【问题标题】:CoreLocation thread crash Crashed: com.apple.CoreLocation.ConnectionClient.0x16fcb870.eventsCoreLocation线程崩溃崩溃:com.apple.CoreLocation.ConnectionClient.0x16fcb870.events
【发布时间】:2016-11-09 07:43:17
【问题描述】:

我在我们的生产应用程序的 Apple 的 CoreLocation 线程中遇到了这个崩溃。我无法在我的测试中重现它,也很难弄清楚它在 CoreLocation 内部。目前它的人口比例很少,但我可以看到它越来越大。

   Crashed: com.apple.CoreLocation.ConnectionClient.0x16fcb870.events
0  CoreLocation                   0x2aa2db54 CLClientCreateIso6709Notation + 53675
1  CoreLocation                   0x2aa2dc7b CLClientCreateIso6709Notation + 53970
2  CoreLocation                   0x2aa2de03 CLClientCreateIso6709Notation + 54362
3  CoreLocation                   0x2aa2dcfb CLClientCreateIso6709Notation + 54098
4  CoreLocation                   0x2aa30f59 CLClientCreateIso6709Notation + 66992
5  CoreLocation                   0x2aa31089 CLClientCreateIso6709Notation + 67296
6  CoreFoundation                 0x24954699 <redacted> + 16
7  CoreFoundation                 0x2493f698 <redacted> + 120
8  CoreFoundation                 0x24948575 CFDictionaryApplyFunction + 172
9  CoreLocation                   0x2aa3036d CLClientCreateIso6709Notation + 63940
10 CoreLocation                   0x2aa2edaf CLClientCreateIso6709Notation + 58374
11 libxpc.dylib                   0x247816e5 <redacted> + 40
12 libxpc.dylib                   0x24784413 <redacted> + 122
13 libxpc.dylib                   0x2478436d <redacted> + 48
14 libxpc.dylib                   0x24784319 <redacted> + 64
15 libxpc.dylib                   0x2477fbb9 <redacted> + 1512
16 libdispatch.dylib              0x245c75a1 <redacted> + 516
17 libdispatch.dylib              0x245cd9ed <redacted> + 592
18 libdispatch.dylib              0x245c689b <redacted> + 362
19 libdispatch.dylib              0x245cd9ed <redacted> + 592
20 libdispatch.dylib              0x245c6e17 <redacted> + 282
21 libdispatch.dylib              0x245cd9ed <redacted> + 592
22 libdispatch.dylib              0x245c6e17 <redacted> + 282
23 libdispatch.dylib              0x245cf20d <redacted> + 400
24 libdispatch.dylib              0x245cf07b <redacted> + 94
25 libsystem_pthread.dylib        0x24762e0d _pthread_wqthread + 1024
26 libsystem_pthread.dylib        0x247629fc start_wqthread + 8

我们正在使用 CoreLocation 来监控和确定特定信标区域的范围,这里是查找附近信标的代码。 另请注意,HPBeaconManager 在 App 进入前台时重新初始化,并且来自 crashlytics 报告 看起来当应用程序进入前台时会发生这种情况。销毁 CLLocationManger 对象并重新初始化是否可以 导致这个问题?任何正确方向的指导将不胜感激。

这是调用代码。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        self.beaconManager = HPBeaconManager()
        self.beaconManager?.startMonitoring()
        return true;
}

func applicationDidBecomeActive(application: UIApplication)
          if (( self.beaconManager ) != nil){
            self.beaconManager = nil;
        }
        self.beaconManager = HPBeaconManager()
        self.beaconManager?.startRanging()
}

这是 HPBeaconManager 实现。

class HPBeaconManager: NSObject , CLLocationManagerDelegate {

    var propertyBeaconRegion: HPBeaconRegion?
    var agentBeaconRegion: HPBeaconRegion?
    var locationManager: CLLocationManager = CLLocationManager()
    var delegate:BeaconManagerDelegate?
    var beacons:NSMutableSet = NSMutableSet()

    override init() {
        super.init()
        self.propertyBeaconRegion = HPBeaconRegion(proximityUUID: HPBeaconCommons.propertyUUID, major: CLBeaconMajorValue(1), identifier: HPBeaconCommons.propertyBeaconIdentifier)
        self.agentBeaconRegion = HPBeaconRegion(proximityUUID: HPBeaconCommons.agentUUID, major: CLBeaconMajorValue(1), identifier: HPBeaconCommons.agentBeaconIdentifier)

        self.locationManager = CLLocationManager()
        self.locationManager.delegate = self
    }

    func startMonitoring() -> Void {

        self.locationManager.startMonitoringForRegion(self.agentBeaconRegion!)
        self.locationManager.startMonitoringForRegion(self.propertyBeaconRegion!)

        self.locationManager.startRangingBeaconsInRegion(self.agentBeaconRegion!)
        self.locationManager.startRangingBeaconsInRegion(self.propertyBeaconRegion!)

        strongSelf.locationManager.startUpdatingLocation()
    }

    func stopMonitoring() -> Void {
        self.locationManager.stopMonitoringForRegion(self.agentBeaconRegion!)
        self.locationManager.stopMonitoringForRegion(self.propertyBeaconRegion!)

        self.locationManager.stopRangingBeaconsInRegion(self.agentBeaconRegion!)
        self.locationManager.stopRangingBeaconsInRegion(self.propertyBeaconRegion!)

        self.locationManager.stopUpdatingLocation()
    }

    func startRanging() {
        self.locationManager.startRangingBeaconsInRegion(self.agentBeaconRegion!)
        self.locationManager.startRangingBeaconsInRegion(self.propertyBeaconRegion!)
    }

    func locationManager(manager: CLLocationManager, didStartMonitoringForRegion region: CLRegion) {
        NSLog("\n ************** Monitoring starts for region %@", region.identifier)
    }

    func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {

    }

    func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
        NSLog("\n ************** Did Enter Region")
    }

    func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {

    }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

        var locationArray = locations as NSArray
        if  locationArray.count > 0 {
            var locationObj = locationArray.lastObject as! CLLocation
            var coord = locationObj.coordinate
            let loationString = "\(coord.latitude)|\(coord.longitude)"
        }
    }

    func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) {

        if beacons.count > 0 {
            let nearestBeacon:CLBeacon = beacons[0] as! CLBeacon
            ....    
        }
    }

    func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        if status == .AuthorizedAlways {
            NSLog("Location Access (Always) granted!")
            dispatch_after(dispatch_time_t(0.5), dispatch_get_main_queue(), { [weak self] in
                if let strongSelf = self {
                    if manager.rangedRegions.isEmpty {
                        NSLog("Ranged region is empty")
                    }
                    strongSelf.startMonitoring()
                }
            })

        } else if status == .AuthorizedWhenInUse {
            NSLog("Location Access (When In Use) granted!")
            dispatch_after(dispatch_time_t(0.5), dispatch_get_main_queue(), { [weak self] in
                if let strongSelf = self {
                    if manager.rangedRegions.isEmpty {
                        NSLog("Ranged region is empty")
                    }
                    strongSelf.startMonitoring()
                }
            })
        } else if status == .Denied || status == .Restricted {
            NSLog("Location Access (When In Use) denied!")
        }
    }

    deinit {
        NSLog("BeaconManager cleanup")
        self.locationManager.stopUpdatingLocation()
        self.locationManager.delegate = nil
    }
}

【问题讨论】:

  • 这不会回答您的问题,但我建议您对代码采用“Swiftier”语法。到处都是无用的分号,当你什么都不返回时不需要指定“Void”,使用 NSLog 简单的打印就可以了。
  • 已编辑.. 感谢您的建议.. 我正在使用 NSLogs,因为在物理设备上执行时,NSLog 语句出现在设备的控制台中,而 println 仅出现在调试器控制台中。

标签: ios swift core-location ibeacon


【解决方案1】:

虽然不明显这会导致崩溃,但在applicationDidBecomeActive 中启动CLBeaconManager 的方式可能会导致问题。

每当应用程序进入前台时,都会构造一个新的HPBeaconManager,并创建一个新的CLLocationManager 对象。旧的HPBeaconManager 被取消引用,导致ARC 对它进行垃圾收集并在以后销毁它,此时deinit() 方法将被调用并且第一个locationManager 的委托设置为nil。在此之前,仍然会在旧的 HPBeaconManager 上调用委托方法,同时新的 HPBeaconManager 处于活动状态。

理论上,这一切都应该有效。但是,根据 ARC 清理旧的 HPBeaconManagerCLLocationManager 实例需要多长时间,用户可能会在前台来回切换应用程序,最终可能会同时出现相当多的活动.如果这会产生微妙的错误,可能导致CoreLocation 内部崩溃,我不会感到惊讶。

我建议重构HPBeaconManager,这样当应用程序进入前台时,您可以根据需要重新初始化它,而无需创建新的对象实例。避免这种对象流失可能会使应用更加稳定。

【讨论】:

  • 感谢 davidgyoung 的回答,我在应用程序进入前台时创建新的 CLLocationManger 对象的唯一原因是因为我想在前台重新启动测距。从我的测试中我发现CLLocationManger 在没有与之关联的rangedRegions 时重新启动,我的意思是它应该是全新的对象。无论如何我们可以用现有的CLLocationManager 对象重新开始测距吗?所以我不必每次应用程序进入前台时都再次创建/销毁它。
  • 是否有重启测距的具体原因?你有什么理由不能保持测距吗?如果您不确定它是否已启动,您可以安全地再次调用 start 方法。如果您确实出于某种原因确实需要重新启动,只需调用 stop 然后使用相同的 CLLocationManager 对象重新开始。如果它有什么不同,我会感到惊讶。
  • 是的,你是对的@davidgyoung。我不需要重新开始测距,因此不需要新的CLLocationManger 对象。事实上它总是在测距,但有一个小错误。我在Set 中收集远程信标,它会忽略那些已经在Set 中或已处理的信标,遗憾的是我在测距时删除了所有日志语句,因为它污染了控制台,所以我不知道发生了什么在。简单的解决方法是,当应用程序进入前台时,我刚刚清除了 Sat,并且所有信标都得到了重新处理。这解决了我的问题。感谢您为我指明正确的方向。
猜你喜欢
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-29
相关资源
最近更新 更多