iOS 6上的长期后台任务执行

时间:2014-02-26 13:50:19

标签: ios ios6 background-process

我正在创建一个在线商店风格的应用程序,用户可以在iPad上浏览不同的产品并订购这些产品。订购流程包括使用用户的数据和他想订购的相关产品创建xml文件。但有时可能会出现这样的情况:用户目前没有互联网连接,我想创建一些机制,每隔x分钟检查一次活动的互联网连接,然后尝试发送order-xml。它应重复此步骤,直到它连接到网络,然后在发送所有离线购物车时停止它。

我已经在网上搜索但只找到了在iOS 7上进行此操作的方法(使用UIBackgroundModes - fetch)。但我不想使用iOS 7,因为该应用程序已经完成,我不打算为iOS 7重新设计它(它是一个企业应用程序)。据我所知,iOS 6上当前的背景执行时间限制在15分钟左右,这是正确的吗?

关于如何解决的任何想法?

感谢。

编辑: 我在- (void)applicationDidEnterBackground:(UIApplication *)application

中尝试了以下内容
self.queue = [[NSOperationQueue alloc] init];
[self.queue addOperationWithBlock:^{
    [[InstanceHolder getInstance] startNetworkTimer];
}];

以下是接下来应该发生的事情:

- (void) startNetworkTimer{
    if ([CommonCode getAllOfflineCartsForClient:nil].count > 0){
        NSTimer *pauseTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(offlineCartLoop:) userInfo:nil repeats:YES];
    }

}

- (void) offlineCartLoop:(id)sender{
    if([CommonCode isInternetConnectionAvailable]){
        [self sendOfflineCarts];
        [sender invalidate];
    }
}

startNetworkTimer被调用,但它不会调用offlineCartLoop函数: - (

编辑2:

我认为计时器问题就是问题。我现在正在调用offlineCartLoop函数:

self.queue = [[NSOperationQueue alloc] init];
[self.queue addOperationWithBlock:^{
    [[InstanceHolder getInstance] offlineCartLoop:nil];
}];

并将offlineCartLoop函数更改为:

- (void) offlineCartLoop:(id)sender{
    if([CommonCode isInternetConnectionAvailable]){
        [self sendOfflineCarts];
    }else{
        [NSThread sleepForTimeInterval:10.0];
        [self offlineCartLoop:nil];
    }
}

似乎工作,但这会永远运行吗?还有什么我需要照顾的吗?

2 个答案:

答案 0 :(得分:2)

没有你想要的解决方案 - 除非它在beginBackgroundTaskWithExpirationHandler授予的时间窗口内,否则无法在后台中定期检查每N分钟。 然而仅允许iOS6及更早版本的10分钟执行时间,或iOS7约3分钟。

如果您的应用不需要,您不能作弊并尝试使用后台模式,即使后台模式也不允许您随时自由运行。 即使iOS 7中的新背景模式也不允许您按计划运行。

即使你不想迁移到iOS7,你最好的最好的是iOS7 - 后台获取是相关模式(即使你不推拿)。使用该后台模式,您将有机会执行而不是在您决定时,仅在操作系统决定时 - 并且其频率取决于用户如何使用您的应用程序。 使用iOS6,您的选择更受限制。

请参阅iOS: Keep an app running like a service

基本上没有连续后台执行,也没有定期后台执行,也没有应用决定何时在后台运行。

如果用户在使用您的应用下订单时没有互联网连接,那么无论如何您都应该通知他们(如果您不知道您的应用可能会被应用商店拒绝)也许告诉他们稍后再试。

如果他们处于飞行模式,用户将知道他们处于飞行模式,如果有临时中断(例如电话在电梯或隧道中),那么您的应用程序可以继续尝试,只要它是能够 - 在前台继续尝试每一分钟,然后当你切换到背景时你知道你还剩10分钟,继续尝试直到10分钟已经过期,然后向用户发布本地通知,通知他们应用程序无法由于缺乏连接而下订单。如果用户点击通知并启动您的应用,那么该应用将有机会再次重试。

如果仍然无法建立连接,那么就可以了,但您将有机会再次启动重试算法。但至少你已通知用户他们的订单没有通过。

答案 1 :(得分:0)

如果你需要知道的是数据连接是否以及何时可用,我建议反过来:而不是查询数据连接,让数据连接可用时通知你的应用程序。效率更高。

关于这个问题,我建议使用Reachability:您可以打电话询问是否可以访问特定的URL,并在连接可用时立即执行代码块。

Reachability *reach = [Reachability reacabilityWithHostName:@"www.myservice.com"];

...

reach.reachableBlock = ^(Reachability *reach) {
    // Process the requests queue
    // You should implement the method below
    [self processQueue];
}

...

if ([reach isReachable]) {
    // Upload the XML file to the server
    // You should implement the method below
    [self uploadToServer:myRequest];
} else {
    // Enqueue your request somewhere, for example into an NSArray
    // You should implement the method below
    [self addToQueue:myRequest];
}

上面的代码是一个展示(它不能正常工作),用它作为参考。我可以说reach变量应该是类属性或数据成员,并且应该初始化一次。 此外,如果您将请求排入NSArray,请确保以线程安全模式执行

或者,可达性也可以在连接可用时通过NSNotification通知 - 这是实现相同结果的不同方式。由您决定哪一个更符合您的需求。