Как извлечь выгоду из Apollo iOS Closure? Как "обернуть" замыкание в функцию?
Я использую Apollo iOS для получения запросов GraphQL. Я хочу переместить apollo.fetch()
закрытие запросов к отдельной функции в классе. Этот класс будет содержать статическую ссылку на клиент apollo, а также функции для выполнения мутаций и запросов GraphQL.
Я пытаюсь следующее:
static func fetchQueryResults() -> CountriesQuery.Data.Country?{
var myResult: CountriesQuery.Data.Country?
myResult = nil
apollo.fetch(query: countriesQuery) { (result, error) in
print(result?.data)
myResult = result?.data //this line causes error
}
return myResult
}
Всякий раз, когда я добавляю строку myResult = result?.data
Я получаю сообщение об ошибке Общий параметр 'Запрос' не может быть выведен.
Однако, когда строка закомментирована, она работает нормально, но, очевидно, функция не имеет смысла. В конце концов я хотел бы обобщить эту функцию, чтобы я мог передать в нее запрос, но как мне получить данные из этого базового замыкания?
По сути, вопрос в том, как мне "обернуть" замыкание в функции?
Смысл этой функции в том, чтобы иметь возможность получить количество строк для раздела табличного представления в функции:
override func tableView(_ tableView:UITableView, numberOfRowsInSection section: Int -> Int{
return fetchQueryResults.count
}
Однако представление загружается до запуска этой функции. Я думаю, это потому, что apollo.fetch()
работает асинхронно?
0 ответов
В настоящее время я использую Apollo iOS версии 0.16.0, которая является последней версией https://github.com/apollographql/apollo-ios
Есть несколько изменений, связанных с версией ниже 0.13.0, вы можете ознакомиться с примечаниями к выпуску 0.13.0 - Не используйте(result, error)
потому что они переключились с кортежа параметров, допускающих значение NULL, на результат.
Попробуйте использовать что-то вроде этого:
Apollo.shared.client.fetch(query: GetProductQuery(id: id)) { results in
do {
if let gqlErrors = try results.get().errors {
if(!gqlErrors.isEmpty) {
apiResponseError.message = gqlErrors[0].message
publishSubject.onError(apiResponseError)
}
return
}
guard let gplResult = try results.get().data?.getProduct else {
apiResponseError.message = "Error getting results"
publishSubject.onError(apiResponseError)
return
}
publishSubject.onNext(gplResult)
} catch let errorException {
apiResponseError.message = errorException.localizedDescription
publishSubject.onError(apiResponseError)
}
}
Всякий раз, когда я добавляю строку myResult = result?.Data, я получаю сообщение об ошибке. Общий параметр "Запрос" не может быть выведен.
Пара вещей, которые могут это исправить:
добавлять
import Apollo
в этот файл Swift. Вероятно, он у вас уже есть, но если вы создадите свойapollo
экземпляр с использованием статического служебного класса, это могло быть возможно.Отбросьте
, error
в вашем закрытии, так что это просто{ result in
. Я думаю, что это старый синтаксис, который есть во многих учебных пособиях, ноerror
теперь является частьюresult
сам.
Однако представление загружается до запуска этой функции. Я думаю, это потому, что apollo.fetch() работает асинхронно?
По умолчанию запускается DispatchQueue.main
, но вы можете использовать fetch()
вызов функции и укажите, на каком DispatchQueue вы хотите, чтобы он запускался (например, когда вы вводите "выборку" в xCode, автозаполнение фактически покажет его как две разные сигнатуры функции: одна, которая скрывает все параметры со значениями по умолчанию, а вторая, где вы можете явно указать каждый параметр).
В общем, хороший образец для асинхронной загрузки данных в табличном представлении:
var countries: [Country] = [Country]()
func viewDidLoad() {
super.viewDidLoad()
apollo.fetch(query: countriesQuery) { result in
self.countries.removeAll() // clear the old data
// unpack each Country from result
// add to countries array
self.tableView.reloadData() // tell the table view to refresh
}
}
override func tableView(_ tableView:UITableView, numberOfRowsInSection section: Int -> Int{
return countries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let country = countries[indexPath.row]
let yourCell: YourCell = tableView.dequeueReusableCell(withIdentifier: "yourCellKey", for: indexPath) as! YourCell
yourCell.setCountry(country)
return yourCell
}