直接访问缓存
Apollo iOS 提供了直接使用类型安全的生成 操作 模型来读取和更新缓存功能。这为在纯 Swift 代码中访问您的缓存数据提供了一个强类型接口。
关于ApolloStore
提供了通过 ReadTransaction
和 ReadWriteTransaction
访问缓存的 API。
本文解释了如何直接访问缓存数据。要了解如何在执行 GraphQL 操作 时使用缓存与网络请求来获取数据,请参阅我们的 本地缓存数据获取。
读取缓存数据
您可以使用 ApolloStore.withinReadTransaction(_:callbackQueue:completion:)
直接从本地缓存中读取数据。事务块提供了一个 ReadTransaction
。
A ReadTransaction
可以被用来读取您的任何生成型的GraphQL查询或片段。
// Read from a GraphQL Queryclient.store.withinReadTransaction({ transaction inlet data = try transaction.read(query: HeroNameQuery(episode: .jedi))print(data.hero?.name)})// Read from a GraphQL fragmentclient.store.withinReadTransaction({ transaction -> HeroDetails inlet data = try transaction.readObject(ofType: HeroDetails.self,withKey: "Hero:123")print(data.hero?.name)})
写入缓存数据
您可以使用ApolloStore.withinReadWriteTransaction(_:callbackQueue:completion:)
将数据写入本地缓存。事务块提供ReadWriteTransaction
。除了能够在缓存中写入数据外,ReadWriteTransaction
还具有与ReadTransaction
相同的所有功能。要写入缓存数据,您需要定义一个LocalCacheMutation
。
定义本地缓存变体
与读取缓存数据读取缓存数据一样,写入缓存也使用类型安全的生成模型。但因为你操作和片段的生成模型是不可变的,所以你不能改变这些模型中的值来将它们写入缓存。为了写入缓存,你可以定义一个LocalCacheMutation
。
一个LocalCacheMutation
只是表明为本地缓存突变的GraphQL查询或片段定义,使用Apollo iOS特定指令 @apollo_client_ios_localCacheMutation
。
当定义了这个指令的查询或片段时,代码生成引擎将生成一个可变模型,该模型可以用ReadWriteTransaction
写入缓存数据。
你的查询定义也可以定义变量,以使用输入参数对这些操作的字段进行缓存数据突变。更多详细信息请参阅我们的操作参数文档。
query HeroNameLocalCacheMutation($episode: Episode!) @apollo_client_ios_localCacheMutation {hero(episode: $episode) {idname}}
fragment MutableHeroDetails on Hero@apollo_client_ios_localCacheMutation {idname}
为你生成的 变更 模型将具有可变 字段(使用var
而不是 let
)。在一个可变模型上生成获取器和设置器意味着它们比不可变生成的模型更大。
将缓存变更与网络操作分离
将一个 查询 标记为 LocalCacheMutation
后,该缓存变更生成的模型不再符合 GraphQLQuery
。这意味着你不能再将该缓存变更作为查询操作。
根本原因是,缓存变更模型是 可变的,而网络响应数据是 不可变的。缓存变更设计为仅访问和变更所需的数据。
如果我们的缓存变更模型是可变的,那么在 ReadWriteTransaction
之外对其进行变更不会将任何更改持久保存到缓存中。此外,可变数据模型需要的生成代码量几乎是不可变模型的两倍。通过维护不可变模型,我们避免了这种混淆并减少了我们的生成代码。
避免创建整个查询操作的可变版本。相反,定义可变片段或查询以仅变更必要的字段。
将本地缓存变更写入缓存
一旦你生成了可变查询模型,你可以使用 ReadWriteTransaction.update()
.
store.withinReadWriteTransaction({ transaction inlet cacheMutation = HeroNameLocalCacheMutation(episode: .CLONES)try transaction.update(cacheMutation) { (data: inout HeroNameLocalCacheMutation.Data) indata.hero.name = "General Kenobi"}let queryData = try transaction.read(query: HeroNameQuery(episode: .jedi))print(queryData.hero?.name) // "General Kenobi"})
将可变片段写入缓存
要写入可变 fragment 的数据,请使用 ReadWriteTransaction.updateObject(ofType:withKey:variables:_:)
。您需要传递要更新的对象的缓存键以及可变 fragment。
关于标准化缓存中的缓存键的更多信息,请参阅我们的关于 标准化缓存响应 的文档。
store.withinReadWriteTransaction({ transaction intry transaction.updateObject(ofType MutableHeroDetails.self,withKey: "Hero:123") { (data: inout MutableHeroDetails) indata.hero.name = "General Kenobi"let queryData = try transaction.read(query: HeroNameQuery(episode: .jedi))print(queryData.hero?.name) // "General Kenobi"}})
删除缓存数据
目前有三种删除方法可用
ApolloStore.clear
立即从缓存中删除所有数据。
ReadWriteTransaction.removeObject(for):
删除给定
CacheKey
的单个对象。ReadWriteTransaction.removeObjects(matching):
删除所有具有与给定模式匹配的
CacheKey
的对象。模式匹配是 不区分大小写。对于内存缓存,它相当于检查缓存键 包含 模式,SQLite 缓存将执行LIKE
查询以删除对象。此方法可能非常慢,具体取决于缓存中的记录数量,建议在后台队列上调用此方法。
`removeObject(for:)` 和 `removeObjects(matching:)` 函数仅删除对象的级别。它们不能删除对象中的单个属性,也不能删除指向对象的引用。
从缓存中删除对象不会执行级联删除。也就是说,如果您删除一个引用另一个对象的对象,引用将被删除,但那个其他对象将不会被删除并保留在缓存中。同样,如果您删除一个对象,在尝试再次加载该对象时,对该对象的引用将不会被删除,它们将简单地失败,导致缓存未命中。
这意味着如果您打算删除某个内容,务必确保您
A) 确定不再需要它
或
B) 对您的缓存策略可能触发额外的获取(如果丢失的值导致读取失败)持开放态度
注意:目前还没有删除单个属性值的方法。例如,调用 try transaction.removeRecord(for: "2001.name")
不会执行任何操作,因为没有以 "2001.name"
为缓存键的记录,因为 name
是 标量 字段。
按缓存键删除对象
通过缓存密钥删除对象可以让您在不删除整个缓存的情况下清除过时或不必要的数据。
在 Apollo iOS 中,您可以为您的对象配置自定义缓存密钥。使用自定义缓存 ID 的缓存条目的密钥将具有格式 `${ObjectType}:${CustomCacheKey}`。
在此示例中,我们已经配置了对缓存使用 id
字段
static func cacheKeyInfo(for type: Object, object: JSONObject) -> CacheKeyInfo? {try? CacheKeyInfo(jsonValue: object["id"])}
这表示对于具有 id
字段的每个对象,其缓存 ID 将是该字段的值。
如果您已从前端获取具有 ID "2001"
的 Book
对象,该对象在缓存中的条目密钥将是 "Book:2001"
。要从缓存中删除此对象,您可以在 ReadWriteTransaction
中调用 transaction.removeObject(for: "Book:2001")
。这将从缓存中删除具有该密钥的条目,以及与它相关联的所有标量属性和它所存储的其他对象的引用。
我们还可以从缓存中删除特定对象的实例。要从缓存中删除所有的 Book
对象,您可以使用 transaction.removeObjects(matching: "Book:")
。