[英]Efficiently sync data in 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循环以同步我的数据并将其发送到服务器。(所有调用都是异步的)
2)如您所见,我已经使用了activeSyncCounter 。 我之所以这样使用,是因为用户可以立即打开和退出该应用程序,这样直到第一个完成时才可以再次调用服务器API。
现在这是我的疑问。
1)首先,当我收到来自服务器的响应时,当数据更多时,通过for循环进行更新需要花费时间,并且我的UI变得无响应。 因此,为了对此进行改进,我需要在调度队列中运行for循环代码。 还是他们有其他更好的方法吗?
另外,更新完成后,当应用程序进入后台时,我是否需要在应用程序进入后台时调度队列?
2)其次,它们是使用activeSyncCounter的替代方法吗?
您(几乎)永远都不想在主线程上执行任何同步I / O操作(包括网络操作),因此对您来说,第一个问题是,您应该使用异步联网API或将同步操作移至其他线程-派遣队列是做到这一点的一种方法。
关于您的第二个问题,我不知道肯定存在“更好”的方式,但是有不同的方式。 我可能建议的一件事是将检查移到callServerAPI
,以简化调用该方法的代码。 (即,一次编写检查代码,而不是在调用服务器API的任何地方编写。)
重要的是,通过调用完成模块来构建网络操作以运行异步并完成操作。 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)重构网络代码以通过调用一个块来异步运行并完成操作;(2)提出一种方案来限制您运行网络请求的频率。
关于后一点,请考虑将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];
编辑 -这是您的网络代码使用块时的外观:
- (void)pushDataWithCompletion:(void (^)(BOOL, NSError))completion;
综合所有这些,您的应用程序委托代码可能看起来最好像这样:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// don't bother if we did this recently (60 sec in this e.g.
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];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.