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)
        }
    }
}
Другие вопросы по тегам