获取数据
以可预测、类型安全的方式获取数据是 Apollo iOS 的核心特性之一。Apollo iOS。在本指南中,您将了解如何对 GraphQL 端点执行操作,并在您的应用程序中使用结果。
先决条件
本页假设您对构建 GraphQL 操作有一定的了解。为了巩固知识,我们建议您阅读此指南阅读此指南并在 Apollo 实验室中练习运行操作。
由于 Apollo iOS 使用的是标准的 GraphQL 语法,您可以在沙盒中运行的任何操作也可以放入.graphql
文件中。
例外:尽管这不是 GraphQL 规范的要求,但 Apollo iOS 要求每个查询都有一个名称。
本页还假设您已经为您的应用程序设置了 Apollo iOS。有关设置的说明,请参阅入门指南入门指南。
定义操作
在 Apollo iOS 中,您执行的每个操作都表示为一个生成类的实例,该类实现了 GraphQLOperation
协议。构造函数 参数 可以用于定义 操作 变量(如果需要的话)。然后,您可以将操作对象传递给一个 ApolloClient
发送操作到服务器、执行该操作,并接收强类型的结果。
GraphQL 操作可以是 查询、 更新,或 订阅。有关使用每种操作类型的详细信息,请参阅它们的单独使用指南。
要生成这些类,我们首先需要定义我们想要执行的 GraphQL 操作。
有关 Apollo iOS 如何生成您的操作类的更多信息,请参阅 代码生成。
假设我们定义了一个名为 HeroName
的 GraphQL 查询:
query HeroName {hero {idname}}
Apollo iOS 将生成一个 HeroNameQuery
类,您可以使用此类进行构造,并将其传递给 ApolloClient.fetch(query:)
:
apollo.fetch(query: HeroNameQuery()) { result inguard let data = try? result.get().data else { return }print(data.hero.name) // Luke Skywalker}
要了解定义参数化操作的方法,请参阅操作参数。
生成的操作模型
操作的结果以不可变结构的层级形式返回,这些结构匹配操作字段的结构。这些结构只包含操作中包含的字段(其他架构字段将省略)。
换句话说,Apollo iOS根据您编写的操作生成结果类型,而不是根据您查询的schema。
例如,给定以下架构
type Query {hero: Character!}interface Character {id: String!name: String!friends: [Character!]appearsIn: [Episode]!}type Human implements Character {id: String!name: String!friends: [Character]appearsIn: [Episode]!height(unit: LengthUnit = METER): Float}type Droid implements Character {id: String!name: String!friends: [Character]appearsIn: [Episode]!primaryFunction: String}
和以下查询:
query HeroAndFriendsNames {hero {idnamefriends {idname}}}
Apollo iOS生成一个类似以下的安全类型模型(省略了以关注类结构为前提的详细信息):
class HeroAndFriendsNamesQuery: GraphQLQuery {struct Data: SelectionSet {let hero: Herostruct Hero: SelectionSet {let id: Stringlet name: Stringlet friends: [Friend]?struct Friend: SelectionSet {let id: Stringlet name: String}}}}
因为HeroAndFriendsNames
查询没有查询appearsIn
,这个属性不是返回结果类型的一部分,在此处不可访问。同样,id
只在Friend
中可访问,不在Hero
中。
因为GraphQL支持可空性,所以您具有编译时的类型安全。如果请求成功,所有查询到的数据(以及只有这些数据)都可以访问。在UI代码中无需处理null字段。
有关如何获取类型安全数据的更多信息,请学习类型条件。
操作结果处理
执行操作的结果是Swift的Result
,其中.success
类包含一个GraphQLResult<Data>
,其中Data
是执行操作生成的根Data
结构体
您可以通过调用try result.get().data
从结果中获取Data
对象。如果您想处理错误或检查结果元数据,您可以像这样对结果进行switch
:
apollo.fetch(query: HeroNameQuery()) { result inswitch result {case .success(let graphQLResult):if let name = graphQLResult.data?.hero?.name {print(name) // Luke Skywalker} else if let errors = graphQLResult.errors {// GraphQL errorsprint(errors)}case .failure(let error):// Network or response format errorsprint(error)}}
注意:操作可以成功,但GraphQLResult
仍然可能包含GraphQLErrors
。有关更多信息,请参阅错误处理。
在后台处理操作结果
默认情况下,Apollo会在主线程上交付操作结果,如果您使用它们来更新UI,这可能是您想要的。
如果希望您的结果处理器在后台队列上调用,fetch(query:)
、perform(mutation:)
和subscribe(subscription:)
函数接受一个可选的queue:
参数。
apollo.fetch(query: HeroNameQuery(),queue: DispatchQueue.global(qos: .background),) { result in... // Will be called on a background queue}
检索本地缓存的-data
Apollo iOS使用归一化缓存来本地存储您的GraphQL响应数据。这样可以您无需等待额外的网络请求即可检索之前已检索的操作数据。您可以使用缓存策略配置您如何与缓存交互。
缓存策略
ApolloClient
的fetch(query:)
方法接受一个可选的cachePolicy
,允许您指定何时从服务器检索结果,以及何时从本地缓存加载数据。
默认情况下,每个请求都使用.returnCacheDataElseFetch
缓存策略,这意味着当数据可用时,将从缓存加载数据,否则从服务器获取。
您可以指定的缓存策略有
.fetchIgnoringCacheData
- 始终从服务器获取,但仍然将结果存储到缓存中。
.fetchIgnoringCacheCompletely
- 始终从服务器获取,不存储缓存中的结果。
- 如果您完全不使用缓存,这种方法比
fetchIgnoringCacheData
更受青睐,原因在于性能。
- 如果您完全不使用缓存,这种方法比
.returnCacheDataAndFetch
- 如果数据可用,则从缓存返回数据;然后执行检索以查看是否有任何更新;将结果存储在缓存中。
- 如果您正在监视查询,这很有用,因为当对服务器的调用返回时,这些查询将得到更新。
.returnCacheDataDontFetch
- 从缓存返回数据;从不从服务器获取。
- 如果没有缓存的-数据,此策略会返回一个错误。
.returnCacheDataElseFetch
- (默认值)- 如果数据可用,则从缓存返回数据;如果缓存数据缺失或 incomplete,则从服务器获取数据并将其存储在缓存中。
- 这是最常见的情况,如果数据不会变更,这是性能最好的方法。
- 如果一旦获取数据,您不需要检查数据更新,您通常应该使用此缓存策略。
如果你希望在请求失败后返回缓存数据,当前推荐的方案是使用拦截链中的 additionalErrorInterceptor
来检查错误是否适用于展示旧数据而不是需传送给用户的情况,然后使用 .returnCacheDataDontFetch
重试策略进行重试。此类设置的示例可以在 缓存相关拦截器测试.
有关结果数据在缓存中的存储方式或配置规范化缓存的更多信息,请参阅 缓存文档。
使用 GET
代替 POST
进行查询
默认情况下,Apollo 使用 POST
发送包含生成的 JSON 的查询到你的 GraphQL 终端。
如果你想让 Apollo 使用 GET
,在配置 RequestChainNetworkTransport
时传递可选参数 useGETForQueries
的值为 true
。这样会设置所有符合 GraphQLQuery
并通过 HTTP 传输发送的查询使用 GET
。
注意: 这是一个开关,将影响所有通过此客户端发送的查询,因此如果你需要某些查询作为 POST
发送,而其他查询作为 GET
发送,你可能需要替换 RequestChainNetworkTransport
。