【问题标题】:iOS: Terminating app in background after a certain period of timeiOS:一段时间后在后台终止应用程序
【发布时间】:2012-01-17 12:51:14
【问题描述】:

我正在尝试在我的应用程序中实现密码锁定功能,让用户可以选择在重新进入需要密码之前必须经过多长时间(类似于操作系统的密码功能)。因此,例如,用户可以选择他们希望在退出应用程序进入后台 5、10、20 分钟后需要密码。

我尝试过以不同方式呈现密码视图,但通常很难找出呈现它的最佳方式,因此我的想法是最好在时间到了,因此我只需要在启动应用程序时显示密码屏幕。

这可能吗?我对解决此问题的方法有两个想法。

1)在应用程序委托中有一个 NSTimer,当应用程序进入后台时启动它,然后当/如果计时器达到设定的分钟数,然后终止应用程序?我可以看到很多事情都出了问题,例如,如果操作系统在计时器完成之前终止了应用程序以释放内存。虽然这不会是一个大问题。

2) 当应用进入后台时设置一个 NSDate 的实例。然后在启动应用程序时,查看该日期是否超过 x 分钟前,并根据该日期显示密码输入屏幕。

我觉得这两个有点不对劲。我对 Timers、RunLoops 等缺乏经验,因此不胜感激。

【问题讨论】:

  • 你可以在你的计时器中调用 exit() ......苹果指南不推荐,但是,它会起作用。
  • 考虑您选择的方法如何与用户在您的应用程序处于后台时更改其设备上的当前日期和时间进行交互。有许多应用程序的“安全性”可以通过这种方式绕过。

标签: objective-c ios nstimer


【解决方案1】:

选项 2 似乎是我们成功使用的一个很好的解决方案。

【讨论】:

    【解决方案2】:

    选项 2. 使用 ApplicationDelegate Lifecycle 方法来驱动它。

    • 应用程序:didFinishLaunchingWithOptions:
    • applicationDidBecomeActive:
    • applicationWillResignActive:
    • applicationDidEnterBackground:
    • applicationWillEnterForeground:
    • applicationWillTerminate:
    • applicationDidFinishLaunching:

    在 applicationWillResignActive 方法中将当前时间戳保存到您的 UserDefaults,并在 applicationWillEnterForeground 中检查当前时间,如果密码间隔已过,请出示您的密码。 (可能最好在您处于活动状态时清除时间戳,以最大程度地减少接听电话和短信等错误触发的机会)

    根据敏感度,您可能希望在进入前台之前准备好视图以隐藏敏感数据,这样它们就不会以解锁状态返回。

    【讨论】:

    • 谢谢@Kevin。这是我正在做的更轻的重量和更好的选择。
    【解决方案3】:

    您可以同时关注两者以获得更好的结果。例如,当应用程序从 didFinishLaunchingWithOptions: 处于活动状态时使用选项 2,当应用程序启用时使用选项 1 - (void)applicationDidBecomeActive:(UIApplication *)application 或 - (void)applicationWillEnterForeground:(UIApplication *)application 选项 1-最简单的方法是在后台运行循环中安排 NSTimer。我建议在您的应用程序委托上实现以下代码,并从 applicationWillResignActive 调用 setupTimer:。

    - (void)applicationWillResignActive:(UIApplication *)application
    {
    [self performSelectorInBackground:@selector(setupTimerThread) withObject:nil];
    }
    -(void)setupTimerThread;
    {
      NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
      NSTimer* timer = [NSTimer timerWithTimeInterval:10 * 60 target:self selector:@selector(triggerTimer:) userInfo:nil repeats:YES];
      NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
      [runLoop addTimer:timer forModes:NSRunLoopCommonModes];
      [runLoop run];
      [pool release];
    }
    
    -(void)triggerTimer:(NSTimer*)timer;
    {
      // Do your stuff
    }
    

    在 appDelegate .h

     UIBackgroundTaskIdentifier bgTask;
    

    在 appDelegate .m

    - (void)applicationDidEnterBackground:(UIApplication *)application
     {
    
    UIApplication*    app = [UIApplication sharedApplication];
    
    // Request permission to run in the background. Provide an
    // expiration handler in case the task runs long.
    NSAssert(bgTask == UIBackgroundTaskInvalid, nil);
    
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        // Synchronize the cleanup call on the main thread in case
        // the task actually finishes at around the same time.
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)
            {
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
    
            }
       });
    }];
    
    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        // Do the work associated with the task.
    
        // Synchronize the cleanup call on the main thread in case
        // the expiration handler is fired at the same time.
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)
            {
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
    
            }
        });
    });
    NSLog(@"app entering background");
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
     If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
     */
    

    }
    或者您可以使用类似这样的方式在后台线程上运行 NSTimer(我故意泄漏线程对象):

    -(void)startTimerThread;
    {
      NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(setupTimerThread) withObject:nil];
      [thread start];
    }
    

    试试上面的代码。我们使用这两个选项对我们来说都很好。祝你好运

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-08
      • 2012-06-11
      • 2015-03-11
      • 2018-03-03
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多