PromsieKit + Alamofire для загрузки постраничных HTTP-данных
Я перенесу некоторый код из RestKit в Alamofire. Я использую MagicalRecord + AlamofireObjectMapper для сопоставления JSON с объектами CoreData.
Я сейчас столкнулся со следующей ситуацией:
Мои данные живут по этому адресу:
http://domain.com/api/resources?start=XX&limit=YY
Теперь я должен сделать это:
- Загрузите первую страницу данных с данного URL, используя размер страницы
50
- Если количество загруженных объектов равно приращению размера страницы,
start
параметр по размеру страницы - Если число меньше размера страницы, объедините все загруженные объекты и верните их вызываемому объекту.
В моем предыдущем примере, не относящемся к Alamofire, я использовал рекурсию для этого, но с PromiseKit, я думаю, мне нужно делать дополнительную цепочку Promises, а не рекурсию вызовов методов.
До сих пор я делал только простые цепочки Promises, так что условная циклическая цепочка и способы ее реализации с помощью PromiseKit для меня немного загадка.
1 ответ
Я придумал подход, который, кажется, работает нормально. Тем не менее, я чувствую, что это может быть гораздо более кратким, так что лучшие ответы или комментарии очень приветствуются.
Я решил совместить рекурсию и обещания (из-за отсутствия лучших решений). Так что я прохожу вдоль 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)
}
}
}