在iOS中高效同步数据
我正在开发应用程序,将数据同步到服务器和从服务器同步,当应用程序进入后台,应用程序变为活动状态。 因为当我同步到多个设备,数据应该在所有设备上更新。
所以这里是我如何做到这一点,
- (void)applicationDidBecomeActive:(UIApplication *)application { if([[AppManager instance].globalManager activeSyncCounter] == 0) { [_webService callServerAPI]; } } - (void)applicationDidEnterBackground:(UIApplication *)application { if([[AppManager instance].globalManager activeSyncCounter] == 0) { [_webService callServerAPI]; } }
让我来解释一下上面的代码
1)我正在调用API来同步我的数据,我遍历for循环来同步我的数据并将其发送到服务器(所有的调用都是asynchronous的)
2)你可以看到我已经使用了activeSyncCounter 。 我使用过这个,因为用户可以立即打开和退出应用程序,以便服务器API不被再次调用,直到第一个完成。
这是我的疑惑。
1)首先,当我收到来自服务器的响应,当数据更多时,需要更新经历for循环,我的用户界面变得没有反应。 所以为了改进,我需要在一个调度队列中运行for循环代码。 或者,他们有更好的方法来做到这一点吗?
另外,更新完成后,当应用程序进入后台时,我也需要调度队列,当应用程序进入后台?
2)其次,是他们使用activeSyncCounter的任何替代
你(几乎)不想在主线程上执行任何同步I / O操作(包括networking操作),所以对于你来说首先问题是,你应该使用asynchronousnetworkingAPI或者把同步操作移到不同的线程 – 派遣队列是这样做的一个方法。
至于你的第二个问题,我不知道确实有一个“更好”的方法,但有不同的方法。 我可能会build议的一件事是将该检查移入callServerAPI
,以简化调用该方法的代码。 (即写一次检查代码,而不是在任何地方调用服务器API。)
build立networking操作来运行asynchronous并通过调用完成块来完成是非常重要的。 NSURLConnection提供了一个名为sendAsynchronousRequest:completionHandler:的便捷方法,它可以做到这一点。
由于您想完成的一些工作必须在进入后台完成,您的应用程序需要保持足够的活动时间才能完成。 苹果在这里提供了一个完整的文章 ,但要点是(调整你的情况的示例代码)…
- (void)applicationDidEnterBackground:(UIApplication *)application { bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{ // Clean up any unfinished task business by marking where you // stopped or ending the task outright. [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // this is your call, modified to use a completion block [_webService callServerAPIWithCompletion:^(id result, NSError *error) { // set state to indicate that the synch finished...see below [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; }
所以我认为你有两点工作要做:(1)重构你的networking代码以运行asynchronous,并通过调用一个块来完成;(2)提出一个scheme来节制你运行networking请求的频率。
在后一点上,考虑将NSDate保存到NSUserDefaults。 那么你可以问:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSDate *lastSynch = [defaults objectForKey:@"MyApp_lastSynch"]; NSTimeInterval sinceLastSynch = -[lastSynch timeIntervalSinceNow]; if (sinceLastCheck < 3600) { // we did the last synch less than an hour ago. skip it for now } else { // do it }
在同步的完成块中,记下您完成的当前时间:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:[NSDate date] forKey:@"MyApp_lastSynch"]; [defaults synchronize];
编辑 – 这是你的networking代码如果使用一个块可能看起来如何:
- (void)pushDataWithCompletion:(void (^)(BOOL, NSError))completion;
把所有这一切放在一起,你的应用程序委托代码可能看起来像这样:
- (void)applicationDidEnterBackground:(UIApplication *)application { // don't bother if we did this recently (60 sec in this eg if ([self timeSinceLastPushData] < 60) return; bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{ [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // this is your call, modified to use a completion block [pushDataWithCompletion:^(BOOL success, NSError *error) { if (success) { NSLog(@"success. right down the time"); [self pushDataComplete]; } else { NSLog(@"error %@, but we'll still tell os that we're done", error); } [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; } - (void)pushDataComplete { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:[NSDate date] forKey:@"MyApp_lastSynch"]; [defaults synchronize]; } - (NSTimeInterval)timeSinceLastPushData { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSDate *lastSynch = [defaults objectForKey:@"MyApp_lastSynch"]; return -[lastSynch timeIntervalSinceNow]; }