私はうまくいくと思われるアプローチを考え出しました。しかし、私はこれがはるかに簡潔であると感じているので、より良い回答やコメントが大歓迎です。
私は再帰と約束を組み合わせることを決めました(より良い解決策がないため)。だから私はcurrentPromise
に沿って渡しています。これはさらに多くのページを読み込む必要があるため、さらにチェーンされています。
第一の方法は、単純に全体のプロセスを開始し、作成された約束を瞬時ようなので、空の配列で満たされる:Promise([Issue]())
:
func loadAllPagedIssues(repository: Repository) -> Promise<[Issue]>{
return loadPagedIssues(repository, limit: Config.apiPageSize, start: 0, currentPromise: Promise([Issue]()))
}
次の方法は、コンテンツをダウンロードし、それを解析する実際の作業を行います。
func loadIssues(url: String, repository: Repository) -> Promise<[Issue]>{
return Promise{ fullfill, reject in
self.manager
.request(.GET, url, headers: self.headers)
.responseArray(keyPath: "issues", context: repository) { (response: Response<[Issue], NSError>) in
switch response.result{
case .Success(let value):
fullfill(value)
case .Failure(let e):
reject(e)
}
}
}
}
最後のメソッドは、渡された結果と現在ロードされている結果を結合します。ページの終わりに達すると、フルフィルメント済みの約束を使用して結果が返され、さらにページをロードする必要がある場合は、別のメソッド呼び出しが発行されます。
func loadPagedIssues(repository: Repository, limit: Int, start: Int, currentPromise: Promise<[Issue]>) -> Promise<[Issue]>{
let url = baseURL + Config.pagedIssuesPath.replaceTokens(
[
"repo": repository.slug,
"limit": String(limit),
"start": String(start)
]
)
let loadPromise = self.loadIssues(url, repository: repository)
return when(loadPromise, currentPromise).then{ newIssues, existingIssues -> Promise<[Issue]> in
let combined = Promise<[Issue]>(newIssues + existingIssues)
if newIssues.count < limit{
// Reached the end of the page
return combined
} else {
return self.loadPagedIssues(repository, limit: limit, start: (start + limit), currentPromise: combined)
}
}
}