客户端 (iOS) 上的核心数据缓存来自服务器策略的数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4878586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Core Data on client (iOS) to cache data from a server Strategy
提问by Pier-Olivier Thibault
I have written many iOS apps that was communicating with the backend. Almost every time, I used HTTP cache to cache queries and parse the response data (JSON) into objective-C objects. For this new project, I'm wondering if a Core Data approach would make sense.
我编写了许多与后端通信的 iOS 应用程序。几乎每次,我都使用 HTTP 缓存来缓存查询并将响应数据 (JSON) 解析为 Objective-C 对象。对于这个新项目,我想知道 Core Data 方法是否有意义。
Here's what I thought:
这是我的想法:
The iOS client makes request to the server and parse the objects from JSON to CoreData models.
iOS 客户端向服务器发出请求,并将对象从 JSON 解析为 CoreData 模型。
Every time I need a new object, instead of fetching the server directly, I parse CoreData to see if I already made that request. If that object exists and hasn't expired, I use the fetched object.
每次我需要一个新对象时,我不是直接获取服务器,而是解析 CoreData 以查看是否已经发出该请求。如果该对象存在且未过期,则使用获取的对象。
However, if the object doesn't exist or has expired (Some caching logic would be applied here), I would fetch the object from the server and update CoreData accordingly.
但是,如果该对象不存在或已过期(此处将应用一些缓存逻辑),我将从服务器获取该对象并相应地更新 CoreData。
I think having such an architecture could help with the following: 1. Avoid unnecessary queries to the backend 2. Allow a full support for offline browsing (You can still make relational queries with DataCore's RDBMS)
我认为拥有这样的架构可以帮助以下方面: 1. 避免对后端进行不必要的查询 2. 完全支持离线浏览(您仍然可以使用 DataCore 的 RDBMS 进行关系查询)
Now here's my question to SO Gods:
现在这是我对诸神的问题:
- I know this kinda requires to code the backend logic a second time (Server + CoreData) but is this overkill?
- Any limitation that I have under estimated?
- Any other idea?
- 我知道这需要第二次对后端逻辑进行编码(服务器 + CoreData),但这是否有点矫枉过正?
- 我低估了任何限制?
- 还有其他想法吗?
回答by codeclash
First of all, If you're a registered iOS Dev, you should have access to the WWDC 2010 Sessions. One of those sessions covered a bit of what you're talking about: "Session 117, Building a Server-driven User Experience". You should be able to find it on iTunes.
首先,如果您是注册的 iOS 开发人员,您应该可以访问 WWDC 2010 Sessions。其中一个会话涵盖了您正在谈论的一些内容:“会话 117,构建服务器驱动的用户体验”。您应该可以在 iTunes上找到它。
A smart combination of REST / JSON / Core Data works like a charm and is a huge time-saver if you plan to reuse your code, but will require knowledge about HTTP (and knowledge about Core Data, if you want your apps to perform well and safe).
REST / JSON / Core Data 的巧妙组合就像一种魅力,如果您计划重用代码,则可以节省大量时间,但需要有关 HTTP 的知识(以及有关 Core Data 的知识,如果您希望您的应用程序运行良好)和安全)。
So the key is to understand REST and Core Data.
所以关键是要了解 REST 和 Core Data。
Understanding RESTmeans Understanding HTTP Methods (GET, POST, PUT, DELETE, ...HEAD ?) and Response-Codes (2xx, 3xx, 4xx, 5xx) and Headers (Last-Modified, If-Modified-Since, Etag, ...)
Understanding Core Data means knowing how to design your Model, setting up relations, handling time-consuming operations (deletes, inserts, updates), and how to make things happen in the background so your UI keeps responsive. And of course how to query locally on sqlite (eg. for prefetching id's so you can update objects instead of create new ones once you get their server-side equivalents).
了解REST意味着了解 HTTP 方法(GET、POST、PUT、DELETE、...HEAD ?)和响应代码(2xx、3xx、4xx、5xx)和标头(Last-Modified、If-Modified-Since、Etag、. ..)
理解核心数据意味着知道如何设计你的模型、设置关系、处理耗时的操作(删除、插入、更新),以及如何在后台让事情发生,让你的 UI 保持响应。当然,如何在 sqlite 上进行本地查询(例如,为了预取 id,您可以在获得服务器端等效项后更新对象而不是创建新对象)。
If you plan to implement a reusable API for the tasks you mentioned, you should make sure you understand REST and Core Data, because that's where you will probably do the most coding. (Existing API's - ASIHttpRequestfor the network layer (or any other) and any good JSON lib (eg. SBJSON) for parsing will do the job.
如果您计划为您提到的任务实现可重用的 API,您应该确保您了解 REST 和核心数据,因为这可能是您进行最多编码的地方。(现有的API - ASIHttpRequest为网络层(或任何其他)和任何好的JSON LIB(如SBJSON解析将做的工作)。
The key to make such an API simple is to have your server provide a RESTful Service, and your Entities holding the required attributes (dateCreated, dateLastModified, etc.) so you can create Requests (easily done with ASIHttpRequest, be they GET, PUT, POST, DELETE) and add the appropriate Http-Headers, e.g. for a Conditional GET: If-Modified-Since.
使这种 API 变得简单的关键是让您的服务器提供 RESTful 服务,并且您的实体持有所需的属性(dateCreated、dateLastModified 等),以便您可以创建请求(使用 ASIHttpRequest 很容易完成,无论是 GET、PUT、 POST, DELETE) 并添加适当的 Http-Headers,例如对于条件 GET:If-Modified-Since。
If you already feel comfortable with Core Data and can handle JSON and can easily do HTTP Request and handle Responses (again, ASIHttpRequest helps a lot here, but there are others, or you can stick to the lower-level Apple NS-Classes and do it yourself), then all you need is to set the correct HTTP Headers for your Requests, and handle the Http-Response-Codes appropriately (assuming your Server is REST-ful).
如果您已经对 Core Data 感到满意并且可以处理 JSON 并且可以轻松地执行 HTTP 请求和处理响应(同样,ASIHttpRequest 在这里有很大帮助,但还有其他的,或者您可以坚持使用较低级别的 Apple NS-Classes 并执行它自己),那么您只需要为您的请求设置正确的 HTTP 标头,并适当地处理 Http-Response-Codes(假设您的服务器是 REST-ful)。
If your primary goal is to avoid to re-update a Core-Data entity from a server-side equivalent, just make sure you have a "last-modified" attribute in your entity, and do a conditional GET to the server (setting the "If-Modified-Since" Http-Header to your entities "last-modified" date. The server will respond with Status-Code 304 (Not-Modified) if that resource didn't change (assuming the server is REST-ful). If it changed, the server will set the "Last-Modified" Http-Header to the date the last change was made, will respond with Status-Code 200 and deliver the resource in the body (eg. in JSON format).
如果您的主要目标是避免从服务器端等效项重新更新 Core-Data 实体,只需确保您的实体中有一个“last-modified”属性,并对服务器执行有条件的 GET(设置“If-Modified-Since” Http-Header 到您的实体“上次修改”日期。如果该资源没有更改(假设服务器是 REST-ful),服务器将响应状态代码 304(未修改) . 如果更改,服务器会将“Last-Modified” Http-Header 设置为上次更改的日期,将响应 Status-Code 200 并在正文中传递资源(例如,以 JSON 格式)。
So, as always, the answer is to your question is as always probably 'it depends'. It mostly depends what you'd like to put in your reusable do-it-all core-data/rest layer.
因此,与往常一样,您的问题的答案总是可能“视情况而定”。这主要取决于您想在可重用的全能核心数据/休息层中放入什么。
To tell you numbers: It took me 6 months (in my spare time, at a pace of 3-10 hours per week) to have mine where I wanted it to be, and honestly I'm still refactoring, renaming, to let it handle special use-cases (cancellation of requests, roll-backs etc) and provide fine-grained call-backs (reachability, network-layer, serialization, core data saving...), . But it's pretty clean and elaborate and optimized and hopefully fits my employer's general needs (an online market-place for classifieds with multiple iOS apps). That time included doing learning, testing, optimizing, debugging and constantly changing my API (First adding functionality, then improving it, then radically simplifying it, and debugging it again).
告诉你数字:我花了 6 个月的时间(在我的业余时间,每周 3-10 小时的速度)让我的位置达到我想要的位置,老实说,我仍在重构,重命名,让它成为现实处理特殊用例(取消请求、回滚等)并提供细粒度的回调(可达性、网络层、序列化、核心数据保存...),. 但它非常干净、精致和优化,希望能满足我雇主的一般需求(具有多个 iOS 应用程序的分类广告的在线市场)。那段时间包括学习、测试、优化、调试和不断更改我的 API(首先添加功能,然后改进它,然后从根本上简化它,然后再次调试它)。
If time-to-market is your priority, you're better off with a simple and pragmatic approach: Nevermind reusability, just keep the learnings in mind, and refactor in the next project, reusing and fixing code here and there. In the end, the sum of all experiences might materialize in a clear vision of HOW your API works and WHAT it provides. If you're not there yet, keep your hands of trying to make it part of project budget, and just try to reuse as much of stable 3'rd-Party API's out there.
如果上市时间是您的首要任务,那么您最好采用简单实用的方法:不要在意可重用性,只需牢记所学,并在下一个项目中重构,在这里和那里重用和修复代码。最后,所有经验的总和可能会在您的 API 的工作方式及其提供的内容的清晰愿景中具体化。如果您还没有到那里,请继续努力使其成为项目预算的一部分,并尝试重用尽可能多的稳定的 3'rd-Party API。
Sorry for the lenghty response, I felt you were stepping into something like building a generic API or even framework. Those things take time, knowledge, housekeeping and long-term commitment, and most of the time, they are a waste of time, because you never finish them.
抱歉回复太长了,我觉得您正在涉足构建通用 API 甚至框架之类的事情。这些事情需要时间、知识、内务和长期承诺,而且大多数时候,它们都是浪费时间,因为你永远不会完成它们。
If you just want to handle specific caching scenarios to allow offline usage of your app and minimize network traffic, then you can of course just implement those features. Just set if-modified-since headers in your request, inspect last-modified headers or etags, and keep that info persistent in your persistet entities so you can resubmit this info in later requests. Of course I'd also recommend caching (persistently) resources such as images locally, using the same HTTP headers.
如果您只想处理特定的缓存场景以允许离线使用您的应用程序并最小化网络流量,那么您当然可以只实现这些功能。只需在您的请求中设置 if-modified-since 标头,检查上次修改的标头或 etag,并将该信息保留在您的持久实体中,以便您可以在以后的请求中重新提交此信息。当然,我也建议使用相同的 HTTP 标头在本地缓存(持久)资源,例如图像。
If you have the luxury of modifying (in a REST-ful manner) the server-side service, then you're fine, provided you implement it well (from experience, you can save as much as 3/4 of network/parsing code iOS-side if the service behaves well (returns appropriate HTTP status codes, avoids checks for nil, number transformations from strings, dates, provide lookup-id's instead of implicit strings etc...).
如果您有能力修改(以 REST-ful 方式)服务器端服务,那么您很好,只要您实施得很好(根据经验,您可以节省多达 3/4 的网络/解析代码iOS 端,如果服务表现良好(返回适当的 HTTP 状态代码,避免检查 nil、字符串、日期的数字转换、提供查找 ID 而不是隐式字符串等......)。
If you don't have that luxury, then either that service is at least REST-ful (which helps a lot), or you'll have to fix things client-side (which is a pain, often).
如果您没有这种奢侈,那么要么该服务至少是 REST-ful(这有很大帮助),要么您必须在客户端解决问题(这通常很痛苦)。
回答by Pier-Olivier Thibault
There is a solution out there that I couldn't try because I'm too far in my project to refactor the server caching aspect of my app but it should be useful for people out there that are still looking for an answer:
有一个我无法尝试的解决方案,因为我的项目太远了,无法重构我的应用程序的服务器缓存方面,但它对于仍在寻找答案的人们应该有用:
It does exactly what I did but it's much more abstracted that what I did. Very insightful stuff there. I hope it helps somebody!
这不正是我没有,但它更抽象那就是我所做的。那里有非常有见地的东西。我希望它可以帮助某人!
回答by Chris Eidhof
I think it's a valid approach. I've done this a number of times. The tricky part is when you need to deal with synchronizing: if client and server can both change things at the same time. You almost always need app-specific merging logic for this.
我认为这是一种有效的方法。我已经这样做了很多次。棘手的部分是当您需要处理同步时:如果客户端和服务器都可以同时更改内容。为此,您几乎总是需要特定于应用程序的合并逻辑。