複数の検索を同期的に行い (つまり、前の要求が完了するのを待ってから次の要求を実行する)、先に進む前にすべての操作が完了するまでブロックします。
しかし、セマフォがあきらめると、ローカル検索の完了ハンドルはブロックされて実行されるように見えます。私は成功せずに多くの試みをしました。
私のコードとログは次のとおりです (コピーしてプレイグラウンドに貼り付けることができます)。
import CoreLocation
import MapKit
func search(_ query: String, in span: MKCoordinateSpan, centered center: CLLocationCoordinate2D, id: Int) {
let semaphore = DispatchSemaphore(value: 0)
//let group = DispatchGroup(); group.enter()
// Run the request for this rect
print("\(#function): local search on the \(id)th portion ")
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = query
request.region = MKCoordinateRegion(center: center, span: span)
if #available(iOS 13, *) {
request.resultTypes = .pointOfInterest
}
let search = MKLocalSearch(request: request)
search.start { response, error in
print("\(id) got \(response?.mapItems.count) items")
semaphore.signal()
}
let s = semaphore
//let s = group
// Wait for the request ot complete
print("\(#function): waiting for the \(id)th portion to complete")
//guard _ = s.wait(wallTimeout: .distantFuture) else {
guard s.wait(timeout: .now() + 5) == .success else {
print("\(#function): ***Warning: \(id)th timeout, job incomplete")
return
}
print("\(#function): \(id)th completed")
}
let rect = CGRect(
x: 48.10,
y: 3.43,
width: 0.09,
height: 0.09
)
let n = 4
let latDelta = rect.width / CGFloat(n)
var latOffs = rect.minX
let queue = OperationQueue()
//queue.maxConcurrentOperationCount = 1
var ops = [BlockOperation]()
// -- Run all asyn loca search requests synchronuously
for i in 0..<n {
// Take the next cut of the original region
let portion = CGRect(
x: latOffs,
y: rect.minY,
width: latDelta,
height: rect.height
)
latOffs += latDelta
ops.append(BlockOperation { [portion, i] in
let center = CLLocationCoordinate2D(latitude: CLLocationDegrees(portion.midX), longitude: CLLocationDegrees(portion.midY))
let span = MKCoordinateSpan(latitudeDelta: CLLocationDegrees(portion.width), longitudeDelta: CLLocationDegrees(portion.height))
search("coffee", in: span, centered: center, id: i)
})
}
queue.addOperations(ops, waitUntilFinished: true)
print("All done")
現在の偽の出力:
search(_:in:centered:id:): local search on the 1th portion
search(_:in:centered:id:): local search on the 2th portion
search(_:in:centered:id:): local search on the 3th portion
search(_:in:centered:id:): local search on the 0th portion
search(_:in:centered:id:): waiting for the 1th portion to complete
search(_:in:centered:id:): waiting for the 3th portion to complete
search(_:in:centered:id:): waiting for the 2th portion to complete
search(_:in:centered:id:): waiting for the 0th portion to complete
search(_:in:centered:id:): ***Warning: 0th timeout, job incomplete
search(_:in:centered:id:): ***Warning: 2th timeout, job incomplete
search(_:in:centered:id:): ***Warning: 1th timeout, job incomplete
search(_:in:centered:id:): ***Warning: 3th timeout, job incomplete
All done
0 got Optional(10) items
2 got Optional(10) items
1 got Optional(10) items
3 got Optional(10) items
[アップデート]
次のように、予期される出力の最後の行に no***Warning
と表示されるはずですAll done
(番号付けの正確な順序は、ネットワークの状態によって異なります)。
search(_:in:centered:id:): local search on the 1th portion
search(_:in:centered:id:): local search on the 2th portion
search(_:in:centered:id:): local search on the 3th portion
search(_:in:centered:id:): local search on the 0th portion
search(_:in:centered:id:): waiting for the 1th portion to complete
search(_:in:centered:id:): waiting for the 3th portion to complete
search(_:in:centered:id:): waiting for the 2th portion to complete
search(_:in:centered:id:): waiting for the 0th portion to complete
0 got Optional(10) items
search(_:in:centered:id:): 0th completed
2 got Optional(10) items
search(_:in:centered:id:): 2th completed
1 got Optional(10) items
search(_:in:centered:id:): 1th completed
3 got Optional(10) items
search(_:in:centered:id:): 3th completed
All done
[UPDATE 2]行のコメントを外すと出力される//queue.maxConcurrentOperationCount = 1
search( :in:centered:id:): 0 番目の部分のローカル検索 2020-03-28 23:49:41 +0000 search( :in:centered:id:): 0 番目の部分が完了するのを待っています 2020-03 -28 23:49:41 +0000 search( :in:centered:id:): ***警告: 0 回目のタイムアウト、ジョブが未完了 2020-03-28 23:49:46 +0000 search( :in:centered:id :): 1 番目の部分のローカル検索 2020-03-28 23:49:46 +0000 search( :in:centered:id:): 1 番目の部分が完了するのを待っています 2020-03-28 23:49:46 + 0000 search( :in:centered:id:): *** 警告: 1 回目のタイムアウト、ジョブが未完了 2020-03-28 23:49:51 +0000 search( :in:centered:id:): 2 回目のローカル検索部分 2020-03-28 23:49:51 +0000 検索 ( :in:centered:id:): 2 番目の部分が完了するのを待っています 2020-03-28 23:49:51 +0000 検索 (:in:centered:id:): ***警告: 2 回目のタイムアウト、ジョブが不完全です 2020-03-28 23:49:56 +0000 search( :in:centered:id:): 3 番目の部分のローカル検索 2020- 03-28 23:49:56 +0000 検索 ( :in:centered:id:): 3 番目の部分が完了するのを待っています 2020-03-28 23:49:56 +0000 検索 ( :in:centered:id:) : ***警告: 3 回目のタイムアウト、ジョブが不完全です 2020-03-28 23:50:01 +0000 すべて完了しました 2020-03-28 23:50:01 +0000 0 は Optional(10) アイテムを取得しました 2020-03-28 23 :50:02 +0000 3 取得 Optional(10) 項目 2020-03-28 23:50:02 +0000 2 取得 Optional(10) 項目 2020-03-28 23:50:02 +0000 1 取得 Optional(10)アイテム 2020-03-28 23:50:02 +0000
注: ところで、\(Date())
各プリントの最後にも追加しました