シミュレーターをiOS16で動かすと、位置情報の許可ダイアログを表示するプログラムで次のような警告が発生しました。
This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the `-locationManagerDidChangeAuthorization:` callback and checking `authorizationStatus` first.
対象箇所のソースはこんな感じです。(抜粋しています。)
class LocationClient: NSObject, ObservableObject, CLLocationManagerDelegate {
var appState: AppState?
@Published var authorizationStatus: CLAuthorizationStatus
private let locationManager: CLLocationManager
private var nowDate: Date?
convenience init(appState: AppState) {
self.init()
self.appState = appState
}
override init() {
locationManager = CLLocationManager()
authorizationStatus = locationManager.authorizationStatus
nowDate = LogDate.all().last?.date
super.init()
// 位置情報サービスをサポートしていない端末(GPSを搭載していない端末)の場合はなにもしない
if !CLLocationManager.locationServicesEnabled() {
print("No location service")
} else {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = 10
self.locationManager.allowsBackgroundLocationUpdates = true //バックグラウンド処理を可能にする
self.locationManager.pausesLocationUpdatesAutomatically = false //ポーズしても位置取得を続ける
self.locationManager.startUpdatingLocation()
print("\(self.locationManager.authorizationStatus.description)")
if self.locationManager.authorizationStatus == .authorizedAlways {
self.locationManager.startUpdatingLocation()
} else {
//ユーザーが位置情報の許可をまだしていないので、位置情報許可のダイアログを表示する
self.requestPermission()
}
}
}
}
警告文を翻訳すると・・・
このメソッドをメインスレッドで呼び出すと、UI が応答しなくなることがあります。代わりに、
DeepLlocationManagerDidChangeAuthorization:
コールバックを待ち、最初にauthorizationStatus
をチェックすることを検討してください。
メインスレッド、つまり直列で実行するなということですね。
では、並列で実行させてみましょう。
CLLocationManagerの設定処理をDispatchQueue.global().asyncで囲いました。
class LocationClient: NSObject, ObservableObject, CLLocationManagerDelegate {
var appState: AppState?
@Published var authorizationStatus: CLAuthorizationStatus
private let locationManager: CLLocationManager
private var nowDate: Date?
convenience init(appState: AppState) {
self.init()
self.appState = appState
}
override init() {
locationManager = CLLocationManager()
authorizationStatus = locationManager.authorizationStatus
nowDate = LogDate.all().last?.date
super.init()
let myQueue = DispatchQueue(label:"myOwnQueue") // ←【追加】
myQueue.async { // ←【追加】
// 位置情報サービスをサポートしていない端末(GPSを搭載していない端末)の場合はなにもしない
if !CLLocationManager.locationServicesEnabled() {
print("No location service")
} else {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = 10
self.locationManager.allowsBackgroundLocationUpdates = true //バックグラウンド処理を可能にする
self.locationManager.pausesLocationUpdatesAutomatically = false //ポーズしても位置取得を続ける
self.locationManager.startUpdatingLocation()
print("\(self.locationManager.authorizationStatus.description)")
if self.locationManager.authorizationStatus == .authorizedAlways {
self.locationManager.startUpdatingLocation()
} else {
//ユーザーが位置情報の許可をまだしていないので、位置情報許可のダイアログを表示する
self.requestPermission()
}
}
}
}
}
無事、警告が出なくなりました。
2024/8/20
読者の方から提供いただいた内容を元に修正いたしました。