我正在处理应用程序,当应用程序进入后台并且应用程序变为活动状态时,我将数据与服务器同步。因为当我同步到多个设备时,应该在所有设备上更新数据。
所以我就是这样做的,
- (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
的任何替代选择答案 0 :(得分:1)
你(几乎)从不想在主线程上进行任何同步I / O操作(包括网络操作),所以首先问题,是的,你应该使用异步网络API或将同步操作移到另一个线程 - 调度队列是一种方法。
至于你的第二个问题,我不知道那里确实是一个更好的"更好的"方式,但有不同的方式。我可能建议的一件事是将该检查移到callServerAPI
中,以便简化调用该方法的代码。 (即编写一次检查代码,而不是在任何调用服务器API的地方。)
答案 1 :(得分:0)
通过调用完成块来构建网络操作以运行异步并完成是非常重要的。 NSURLConnection提供了一种称为sendAsynchronousRequest:completionHandler:的便捷方法,它就是这样做的。
由于您要完成的某些工作必须在进入后台时完成,因此您的应用需要保持足够长的时间才能完成。 Apple provides a complete article here,但要点是(根据您的情况调整示例代码)......
- (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];
}