私はあなたが非同期パターンを採用してお勧めしたいです。例えば、完了ハンドラの成功または失敗の報告、電話番号を非同期に取得する方法があります:
// I don't know what your place structure would look like, but let's imagine an `id`,
// some `info`, and a `phoneNumber` (that we'll retrieve asynchronously).
struct Place {
var id: String
var placeInfo: String
var phoneNumber: String?
init(id: String, placeInfo: String) {
self.id = id
self.placeInfo = placeInfo
}
}
func retrievePlaces(completionHandler: ([Place]?) -> Void) {
let request = ...
let task = session.dataTaskWithRequest(request) { data, response, error in
// your guard statements
do {
// Extract results from JSON response (without `phoneNumber`, though
var places: [Place] = ...
let group = dispatch_group_create()
// now let's iterate through, asynchronously updating phone numbers
for (index, place) in places.enumerate() {
dispatch_group_enter(group)
self.requestPhoneNumber(place.id) { phone in
if let phone = phone {
dispatch_async(dispatch_get_main_queue()) {
places[index].phoneNumber = phone
}
}
dispatch_group_leave(group)
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
completionHandler(places)
}
}
}
task.resume()
}
:
let session = NSURLSession.sharedSession()
func requestPhoneNumber(id: String, completionHandler: (String?) -> Void) {
let request = ...
let task = session.dataTaskWithRequest(request) { data, response, error in
do {
let phoneNumber = ...
completionHandler(phoneNumber)
}
catch {
completionHandler(nil)
}
}
task.resume()
}
次に、あなたの最初の要求、場所の全てを取得し、この非同期requestDetails
を使用します。
これは非同期パターンを採用しています。今回は、ディスパッチグループを使用してリクエストがいつ終了するかを識別します。あなたがこの呼び出すとき、あなたは完了ハンドラパターンを使用したい:
retrievePlaces { phoneNumberDictionary in
guard phoneNumberDictionary != nil else { ... }
// update your model/UI here
}
// but not here
注意を、retrievePlaces
意志が(パフォーマンス上の理由から)、互いに対して同時にこれらの要求を発行します。あなたがそれを拘束したい場合は、セマフォーを使ってそれを行うことができます(セッションのキューではなく、バックグラウンドキューでこれを行うことを確実にしてください)。基本的なパターンは次のとおりです。
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
let semaphore = dispatch_semaphore_create(4) // set this to however many you want to run concurrently
for request in requests {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
performAsynchronousRequest(...) {
dispatch_semaphore_signal(semaphore)
}
}
}
だから、次のようになります。それは、この複雑だとき、私は多くの場合、非同期NSOperation
サブクラスを使用して、同時実行を制限するキューのmaxConcurrentOperationCount
を使用します、
率直に言って
func retrievePlaces(completionHandler: ([Place]?) -> Void) {
let request = ...
let task = session.dataTaskWithRequest(request) { data, response, error in
// your guard statements
do {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
// Extract results from JSON response
var places: [Place] = ...
let semaphore = dispatch_semaphore_create(4) // use whatever limit you want here; this does max four requests at a time
let group = dispatch_group_create()
for (index, place) in places.enumerate() {
dispatch_group_enter(group)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
self.requestPhoneNumber(place.id) { phone in
if let phone = phone {
dispatch_async(dispatch_get_main_queue()) {
places[index].phoneNumber = phone
}
}
dispatch_semaphore_signal(semaphore)
dispatch_group_leave(group)
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
completionHandler(places)
}
}
}
}
task.resume()
}
、しかし、それはこの質問の範囲を超えているようだった。しかし、上記のようなセマフォを使用して並行性を制限することもできます。しかし、結論は、要求を同期的に動作させる方法を理解するのではなく、非同期パターンに従う場合に最高のUXとパフォーマンスを達成することです。
タスク内から 'task.resume()'を呼び出すことはできません。それはコンパイルすべきではありません。 – jtbandes
@jtbandes私は彼が彼の答えにタイプミスがあると思います。 task.resumeを移動するための編集を提出しました。 –
あなたはそれを順番に実行するために大きなパフォーマンスペナルティを支払うつもりです。並行リクエストを許可し、ディスパッチグループを使用してすべて完了したときに通知する方がはるかに優れています。または、より劇的なパフォーマンスの改善を行い、Webサービスをリファクタリングして、電話番号を必要とする複数のID番号のリクエストを送信できるようにします。 – Rob