2

我正在编写一个 iOS 应用程序,用于在参与的零售地点扫描条形码,在客户扫描打印在收据上的二维码后,该地点将代表客户向慈善机构捐款。

如果用户在参与地点停留 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];
}
4

2 回答 2

1

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

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

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

  3. 它应该调用您的 stillInRegion 方法,即使您进入后台也会继续,因此延迟应该继续计算!最后,您应该结束后台任务。为此,请在 sendLocalNotification 方法末尾的 if 块之后添加以下行:

    [[UIApplication sharedApplication] endBackgroundTask:bgTaskIdentifier];

让我们知道这是否有帮助!请原谅我的英语不好!

祝你有美好的一天!

于 2013-06-11T00:37:13.793 回答
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 所拥有的,但略有不同。

于 2013-06-21T18:10:28.433 回答