ios - iOS:CoreData 和 Remote API 同步模式
问题描述
我有这样的问题。
/movies?page=0&size=20
返回分页电影的 api 端点
然后我想在 UITableView 中显示这部电影。所以很容易进行分页和加载电影的下一页。
但现在我想在两者之间添加 CoreData 缓存功能和存储库模式。像这样的东西
MoviesRepository(集成以下两个依赖项) MoviesDao(访问电影的核心数据) MoviesService(进行远程 api 调用)
我认为将核心数据视为单一的事实来源。所以 MoviesRepository -> fetchMovies(page: 2, size: 10) 应该是这样的:
- 调用 MoviesDao 从 CoreData 获取 [20,30) 电影
- 向 MoviesService 发出请求 -> getMovies(page: 2, size: 10)
- 得到响应后,它应该调用类似 MoviesDao -> syncMovies([remoteMovies])
- 然后应该检测核心数据更改并更新表视图中的电影(这里我考虑一些 RxSwift 可观察方法或其他类似功能中的组合框架,可能是 som CoreData nofitications 或 FetchResultsController?
但是这里最关键的是将 CoreData 与远程数据同步,因为同时远程数据可能会更改,并且第 2 页不等于核心数据中的第 2 页,以及如何在不重新获取所有数据的情况下解决此问题。
这是我在一些教程中找到的代码,但它替换了所有数据而不是页面。
private func syncFilms(jsonDictionary: [[String: Any]], taskContext: NSManagedObjectContext) -> Bool {
var successfull = false
taskContext.performAndWait {
let matchingEpisodeRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Film")
let episodeIds = jsonDictionary.map { $0["episode_id"] as? Int }.compactMap { $0 }
matchingEpisodeRequest.predicate = NSPredicate(format: "episodeId in %@", argumentArray: [episodeIds])
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: matchingEpisodeRequest)
batchDeleteRequest.resultType = .resultTypeObjectIDs
// Execute the request to de batch delete and merge the changes to viewContext, which triggers the UI update
do {
let batchDeleteResult = try taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult
if let deletedObjectIDs = batchDeleteResult?.result as? [NSManagedObjectID] {
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: [NSDeletedObjectsKey: deletedObjectIDs],
into: [self.persistentContainer.viewContext])
}
} catch {
print("Error: \(error)\nCould not batch delete existing records.")
return
}
// Create new records.
for filmDictionary in jsonDictionary {
guard let film = NSEntityDescription.insertNewObject(forEntityName: "Film", into: taskContext) as? Film else {
print("Error: Failed to create a new Film object!")
return
}
do {
try film.update(with: filmDictionary)
} catch {
print("Error: \(error)\nThe quake object will be deleted.")
taskContext.delete(film)
}
}
// Save all the changes just made and reset the taskContext to free the cache.
if taskContext.hasChanges {
do {
try taskContext.save()
} catch {
print("Error: \(error)\nCould not save Core Data context.")
}
taskContext.reset() // Reset the context to clean up the cache and low the memory footprint.
}
successfull = true
}
return successfull
}
}
解决方案
推荐阅读
- c# - 如何在 C# 上将 pdf 数字签名到单独的文件中?
- kubernetes - 使用 Prometheus 的平均请求持续时间
- google-chrome - 如何在python中使用autoit单击某些文本或坐标
- google-tag-manager - 谷歌标签管理器阻止 Turbolinks 工作
- c++ - 使用 CMake 构建 ffplay
- r - 遍历文件,划分两个变量并提取结果,包括使用原始文件名称的标识符列
- sql-server - 如何使用存储过程将一行数据添加到一个表,将多行数据添加到另一个表-Microsoft SQL Server Management Studio
- git - git reset --hard 在新的 repo 上暂存后
- python - 有没有办法访问通过python连接到PC的手机中的文件?
- tiddlywiki - 如何制作与其他提琴手的缩略链接?