延迟后台任务有时仅在应用程序返回前台时运行

时间:2013-06-10 23:55:54

标签: ios delay nstimer background-process geofencing

我正在编写一个iOS应用程序,用于扫描参与零售点的条形码,在客户扫描收据上印有的QR码后,该位置将代表客户捐赠给慈善机构。

我想向用户发送本地通知,如果他们在参与的位置60秒或更长时间,提醒他们扫描他们可能从他们在那里购买的收据。

我的问题是,当用户进入某个区域时,我想延迟60秒的通话 - 如果在这60秒后他们仍然在该区域发出本地通知 - 但是,有时会在stillInRegion内调用sendLocalNotification在应用程序返回前台之前不会触发。我相信这与线程有时会在延迟结束之前结束,但我不确定。我已经尝试过在stackoverflow和其他地方(块,nstimers等)可以找到的每种方法,但无济于事。关于如何更好地解决这个问题的任何想法?

- (void) sendLocalNotification:(NSString *)regionId {
NSLog(@"we entered %@ and we're currently in %@", regionId, self.currentRegionId);
if ([regionId isEqualToString:self.currentRegionId]) {// if we're still in the region, send a local notification
    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
    if (localNotif == nil) return;
    NSDate *fireTime = [[NSDate date] addTimeInterval:2]; // adds 2 secs
    localNotif.fireDate = fireTime;
    localNotif.alertBody = [NSString stringWithFormat:@"Did you just visit %@? If so, don't forget to scan your receipt!", regionId];
    localNotif.applicationIconBadgeNumber = [UIApplication sharedApplication].applicationIconBadgeNumber+1;
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
    [localNotif release];
}
}

- (void) stillInRegion:(CLRegion *)region {

NSLog(@"did enter region: %@", region.identifier);

[self performSelector:@selector(sendLocalNotification:) withObject:region.identifier afterDelay:60];
}

- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if (self.didLaunchForRegionUpdate) {
    NSString *path = [DGGeofencingHelper applicationDocumentsDirectory];
    NSString *finalPath = [path stringByAppendingPathComponent:@"notifications.dg"];
    NSMutableArray *updates = [NSMutableArray arrayWithContentsOfFile:finalPath];

    if (!updates) {
        updates = [NSMutableArray array];
    }

    NSMutableDictionary *update = [NSMutableDictionary dictionary];

    [update setObject:region.identifier forKey:@"fid"];
    [update setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];
    [update setObject:@"enter" forKey:@"status"];

    [updates addObject:update];

    [updates writeToFile:finalPath atomically:YES];
} else {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:@"enter" forKey:@"status"];
    [dict setObject:region.identifier forKey:@"fid"];
    NSString *jsStatement = [NSString stringWithFormat:@"DGGeofencing.regionMonitorUpdate(%@);", [dict JSONString]];
    [self.webView stringByEvaluatingJavaScriptFromString:jsStatement];
}
self.currentRegionId = region.identifier;
self.cRegionEnterTime =[NSDate date];
[self stillInRegion:region];
}

2 个答案:

答案 0 :(得分:1)

是否在前台调用了locationManager:didEnterRegion,然后你的应用程序转到后台? 我不太清楚你何时调用这些方法,但你可以尝试按如下方式创建后台任务:

  1. 添加一个名为NSUInteger的属性,例如bgTaskIdentifier,用于存储您的后台任务标识符。
  2. 致电[self stillInRegion:region]之前;添加以下代码:

    bgTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^ {}];

  3. 它应该调用你的stillInRegion方法,即使你去后台也继续,所以延迟应该继续指望!最后,您应该结束后台任务。为此,请在send块之后的sendLocalNotification方法的末尾添加以下行:

    [[UIApplication sharedApplication] endBackgroundTask:bgTaskIdentifier];

  4. 如果有帮助,请告诉我们!对不起,我的英语很差!

    祝你有个美好的一天!

答案 1 :(得分:1)

在我的didEnterRegion方法中,我曾经使用以下代码来实现所需的结果:

 UIApplication*   app = [UIApplication sharedApplication];
    bgTaskIdentifier = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTaskIdentifier];
        bgTaskIdentifier = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:180 target:self  selector:@selector(stillInRegion:) userInfo:region.identifier repeats:NO];

        [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];

        [[NSRunLoop currentRunLoop] run];
    });

非常接近@ lucaslt89的内容,但略有不同。