Iphone 如何异步同步CoreData和REST web服务,同时正确地将任何REST错误传播到UI中
嘿,我正在为我们的应用程序制作模型层 一些要求如下:Iphone 如何异步同步CoreData和REST web服务,同时正确地将任何REST错误传播到UI中,iphone,objective-c,rest,core-data,Iphone,Objective C,Rest,Core Data,嘿,我正在为我们的应用程序制作模型层 一些要求如下: 它应该可以在iPhone OS 3.0+上运行 我们的数据源是一个RESTful Rails应用程序 我们应该使用核心数据在本地缓存数据 客户端代码(我们的UI控制器)应该尽可能少地了解任何网络内容,并且应该使用核心数据API查询/更新模型 我已经查看了WWDC10会话117中关于构建服务器驱动的用户体验的内容,花了一些时间查看了,以及框架 Objective Resource框架本身并不与核心数据通信,只是一个REST客户机实现。核心资源和
-(BOOL)save:(NSError**)error
时,核心资源会向服务器发出所有请求,因此能够向服务器提供正确的底层请求NSError实例。但它会阻止调用线程,直到save操作完成。失败
RestfulCoreData使您的-save:
调用保持不变,并且不会为客户端线程引入任何额外的等待时间。它只关注NSManagedObjectContextDidSaveNotification
,然后在通知处理程序中向服务器发出相应的请求。但是通过这种方式,-save:
调用始终成功完成(好吧,给定的核心数据与保存的更改是一致的),并且实际调用它的客户端代码无法知道save可能由于一些404
或421
或任何服务器端错误而无法传播到服务器。而且,本地存储变得需要更新数据,但服务器永远不知道这些更改。失败
因此,我正在寻找解决所有这些问题的可能解决方案/常见做法:
-save:
调用有什么想法吗?您需要一个回调函数,该函数将在另一个线程(实际发生服务器交互的线程)上运行,然后将结果代码/错误信息放入半全局数据,UI线程将定期检查该数据。确保用作标志的数字的连接是原子的,否则将出现竞争条件-例如,如果错误响应为32字节,则需要一个int(该int应具有原子访问),然后将该int保持在off/false/notready状态,直到写入较大的数据块,然后才写入“true”可以这么说,扳动开关 对于客户端上的相关保存,您必须要么保留该数据,要么在服务器确认之前不保存该数据,确保您有一个kinnf of rollback选项,比如说,删除的方法是服务器失败 请注意,除非您执行完整的两阶段提交过程(客户端保存或删除可能会在服务器发出信号后失败),否则它永远不会是100%安全的,但这至少会花费您两次到服务器的行程(如果您唯一的回滚选项是delete,则可能会花费您4次)
理想情况下,您可以在一个单独的线程上执行整个阻塞版本的操作,但您需要4.0版本。这会成为一个同步问题,不容易解决。我要做的是:在iPhone UI中使用一个上下文,然后使用另一个上下文(和另一个线程)从web服务下载数据。完成后,请执行下面推荐的同步/导入过程,然后在所有内容正确导入后刷新UI。如果在访问网络时出现问题,只需回滚非UI上下文中的更改。这是一系列的工作,但我认为这是最好的方法
有三个基本组成部分:
@protocol NetworkOperationDelegate
- (void)operation:(NSOperation *)op willSendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
- (void)operation:(NSOperation *)op didSuccessfullySendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
- (void)operation:(NSOperation *)op encounteredAnError:(NSError *)error afterSendingRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity;
@end
协议格式当然取决于您的特定用例,但本质上您所创建的是一种机制,通过该机制可以将更改“推”到服务器上
接下来有UI循环来考虑,为了保持代码干净,调用Soice是很好的:并且将这些更改自动地推送到服务器上。您可以为此使用NSManagedObjectContextDidSave通知
- (void)managedObjectContextDidSave:(NSNotification *)saveNotification {
NSArray *inserted = [[saveNotification userInfo] valueForKey:NSInsertedObjects];
for (NSManagedObject *obj in inserted) {
//create a new NSOperation for this entity which will invoke the appropraite rest api
//add to operation queue
}
//do the same thing for deleted and updated objects
}
插入网络操作的计算开销应该相当低,但是,如果它在UI上造成明显的延迟,您可以简单地从保存通知中获取实体ID,并在后台线程上创建操作
如果RESTAPI支持批处理,您甚至可以一次发送整个阵列,然后通知UI多个实体已同步<