Ios 应用程序唤醒进行更新时LocationManager崩溃
虽然它在应用程序处于活动状态时工作正常,但在应用程序终止并唤醒以进行位置更新时会崩溃 处理应用程序的我的代码在Ios 应用程序唤醒进行更新时LocationManager崩溃,ios,swift,crash,cllocationmanager,Ios,Swift,Crash,Cllocationmanager,虽然它在应用程序处于活动状态时工作正常,但在应用程序终止并唤醒以进行位置更新时会崩溃 处理应用程序的我的代码在didfishlaunchwithoptions @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { let locationManager = CLLocationManager() var glat : String
didfishlaunchwithoptions
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var glat : String = ""
var glong : String = ""
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if launchOptions?[UIApplicationLaunchOptionsLocationKey] != nil {
let locationManager = CLLocationManager() //or without this line, both crashes
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
let status = CLLocationManager.authorizationStatus()
if (status == CLAuthorizationStatus.AuthorizedAlways) {
locationManager.startMonitoringSignificantLocationChanges()
}
}
return true
}
这是AppDelegate上的locationmanager委托
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let lat = manager.location?.coordinate.latitude,
let long = manager.location?.coordinate.longitude {
print(glat + " " + glong)
glat = String(lat)
glong = String(long)
//Line 339
updateloc(String(lat), long: String(long))
}
}
将位置信息发送到服务器的函数
func updateloc(lat : String, long : String) {
let session = NSURLSession.sharedSession()
//Line 354
let request = NSMutableURLRequest(URL: NSURL(string: "URLTO/updateloc.php")!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "POST"
let data = "lat=\(lat)&long=\(long)"
request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
let res = response as! NSHTTPURLResponse
dispatch_async(dispatch_get_main_queue(), {
if (res.statusCode >= 200 && res.statusCode < 300)
{
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
var success = 0
if let dictJSON = resultJSON as? [String:AnyObject] {
if let successInteger = dictJSON["success"] as? Int {
success = successInteger
if success == 1
{
print("ok")
}
} else {
print("no 'success' key in the dictionary, or 'success' was not compatible with Int")
}
} else {
print("unknown JSON problem")
}
} catch _{
print("Received not-well-formatted JSON")
}
}
})
}
})
task.resume()
}
当应用程序在startMonitoringSignificantLocationChanges
模式下唤醒进行位置更新时,应用程序崩溃
我真的看不出有什么错误。有人能帮我解决吗?首先,我建议将您的location manager功能移动到一个单独的类,并让您的location类订阅UIApplicationIDFinishLaunchingNotification,以处理应用程序重新启动时发生的情况 实现这一点的一种方法是让您的类A Singleton通过NSNotificationCenter转发位置更新 startMonitoringSignificantLocationChanges将在操作系统终止应用程序时在后台唤醒应用程序(如果已启用) 根据您想要实现的目标,您可以订阅两个不同的事件,并根据应用程序委派事件启动或停止相关的位置服务 作为一个广泛的(在黑暗中拍摄)示例: 请记住,这段代码还没有经过测试,我提取了一个旧项目的部分,由于语言的更新可能会有一些语法错误 总的来说,我们正在这样做:
- 订阅相关通知
- 当应用程序即将终止时,请检查我们是否正在获取位置更新,如果是,请停止标准服务并启动重大更改服务,以便在新更新可用时唤醒应用程序
- 当应用程序唤醒时,它将通知类,该类将决定是否继续跟踪通知更新(基于存储在NSUserDefaults上的值)
我希望这有帮助 文件上说 对于重新启动应用程序的服务,系统会将UIApplicationLaunchOptionsLocationKey添加到启动时传递给应用程序代理的选项字典中。当此密钥存在时,您应该立即重新启动应用程序的位置服务。选项字典不包含有关位置事件本身的信息。您必须配置一个新的location manager对象并委派,然后再次启动位置服务以接收任何挂起的事件 此外,它还说: 连续多次调用此方法[意味着
startMonitoringSignificantLocationChanges
]不会自动生成新事件。但是,在这两者之间调用stopMonitoringSignificantLocationChanges会导致下次调用此方法时发送新的初始事件
这意味着乍一看可能不太清楚。首先,位置更新触发应用程序重新启动的事实并不意味着您可以通过代理的locationManager:didUpdateLocations:
方法立即获得它。第二,如果你在背景中(因此没有重新启动,只是变得活跃!),事情又会不同了。事实上,我看到人们遇到的一个常见问题是,他们不知道自己是处于后台(非活动)还是终止/刚刚重新启动。您甚至无法轻松测试/查看这一点,因为系统终止的应用程序在按两次home按钮时仍会显示。检查XCode的Debug
菜单中Attach to Process…
下显示的列表,查看您的应用程序是否仍在运行(以及在后台运行)(顺便说一句,如果您想使用各种激活或重新启动的方式,通过XCode中的停止按钮终止应用程序会导致这种不一致性)。我之所以在这里提到这一点,是因为很多问题都会问“当我的应用程序再次激活时,为什么会发生X?”而回答的人会做出与提问人不同的假设
无论如何,如果您的应用程序实际上已重新启动,则您的locationManager
变量现在包含一个全新的实例,您应该在调用startMonitoringSignificantLocationChanges
后立即获得更新。我将在下面讨论您可能仍然会遇到的问题。
如果你的应用程序再次激活,你应该调用stopMonitoringSignificantLocationChanges
,然后再次调用startMonitoringSignificantLocationChanges
,以立即获得更新(简而言之:总是先停止,然后再开始,以正确地重新启动,即使你还没有运行,也不会造成任何伤害)
至于问题,我认为这(部分)源于苹果在位置更新后重新启动的方式。在不使用代码的情况下,我不能完全确定发生了什么,但我希望这会有所帮助:
在应用程序中:didFinishLaunchingWithOptions:
方法使用let locationManager=CLLocationManager()
设置本地常量。然后重新启动该程序并触发位置更新。但是,它可能在调用委托的locationManager:didUpdateLocations:
方法之前解除分配,毕竟回调是异步发生的(并且application:didFinishLaunchingWithOptions:
可能在调用之前返回)。我不知道这到底是怎么回事,也不知道为什么会这样,也许这是运气使然,或者这与CLLocationManager内部的工作方式有关。无论如何,我认为接下来会发生的事情是,在locationManager:didUpdateLocations:
中,您不再获得有意义的位置数据,因为负责调用的CLLocationManager
实例不再有效<代码>纬度和低
Crashed: com.apple.main-thread
0 0x10015d998 specialized AppDelegate.updateloc(String, long : String) -> () (AppDelegate.swift:354)
1 0x10015ddf8 specialized AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift:339)
2 0x100159d0c @objc AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift)
3 CoreLocation 0x1893d08b8 (null) + 21836
4 CoreLocation 0x1893ccaac (null) + 5952
5 CoreLocation 0x1893c6e48 (null) + 880
6 CoreFoundation 0x18262cf84 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20
7 CoreFoundation 0x18262c8bc __CFRunLoopDoBlocks + 308
8 CoreFoundation 0x18262ad04 __CFRunLoopRun + 1960
9 CoreFoundation 0x182554c50 CFRunLoopRunSpecific + 384
10 GraphicsServices 0x183e3c088 GSEventRunModal + 180
11 UIKit 0x18783e088 UIApplicationMain + 204
12 0x10015a324 main (AppDelegate.swift:20)
class LocationCommander {
let locationManager = CLLocationManager()
let defaultCenter = NSNotificationCenter.defaultCenter()
//- NSUserDefaults - LocationServicesControl_KEY to be set to TRUE when user has enabled location services.
let UserDefaults = NSUserDefaults.standardUserDefaults()
let LocationServicesControl_KEY = "LocationServices"
init(){
defaultCenter.addObserver(self, selector: #selector(self.appWillTerminate), name: UIApplicationWillTerminateNotification, object: nil)
defaultCenter.addObserver(self, selector: #selector(self.appIsRelaunched), name: UIApplicationDidFinishLaunchingNotification, object: nil)
}
func appIsRelaunched (notification: NSNotification) {
//- Stops Significant Location Changes services when app is relaunched
self.locationManager.stopMonitoringSignificantLocationChanges()
let ServicesEnabled = self.UserDefaults.boolForKey(self.LocationServicesControl_KEY)
//- Re-Starts Standard Location Services if they have been enabled by the user
if (ServicesEnabled) {
self.updateLocation()
}
}
func appWillTerminate (notification: NSNotification){
let ServicesEnabled = self.UserDefaults.boolForKey(self.LocationServicesControl_KEY)
//- Stops Standard Location Services if they have been enabled
if ServicesEnabled {
self.locationManager.stopUpdatingLocation()
//- Start Significant Location Changes to restart the app
self.locationManager.startMonitoringSignificantLocationChanges()
}
NSUserDefaults.standardUserDefaults().synchronize()
}
func updateLocation () {
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized){
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.startUpdatingLocation()
//- Save Location Services ENABLED to NSUserDefaults
self.UserDefaults.setBool(true, forKey: self.LocationServicesControl_KEY)
} else {
//- Unauthorized, requests permissions
}
}
}
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_DEFAULT.rawValue), 0)) {
updateloc(String(lat), long: String(long))
}