UIWindow 的 makeKeyAndVisible 和后台任务

Posted

技术标签:

【中文标题】UIWindow 的 makeKeyAndVisible 和后台任务【英文标题】:UIWindow's makeKeyAndVisible and background task 【发布时间】:2014-09-05 08:39:14 【问题描述】:

我已将后台任务功能添加到我的应用程序中。这是我的应用委托

// AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     
    [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
    [self.window setBackgroundColor:[UIColor blackColor]];

    if (application.applicationState != UIApplicationStateBackground)         
        // Application is launch in because user tap the app icon or from springboard

        if ([application respondsToSelector:@selector(setMinimumBackgroundFetchInterval:)]) 
            [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
        
     else 
        // Application is launch in background mode
    

    RootViewController *rootViewController = [[RootViewController alloc] initByDevice];
    [self.window setRootViewController:rootViewController];
    [self.window makeKeyAndVisible];

    return YES;


- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 

    [[DataManager instance] updateDataWithMaxAttempt:5 block:^(BOOL success, NSArray *newData) 
        if (success) 
            if ([newData count] > 0) 
                completionHandler(UIBackgroundFetchResultNewData);
             else 
                completionHandler(UIBackgroundFetchResultNoData);
            
         else 
            completionHandler(UIBackgroundFetchResultNoData);
        
    ];

这是我的根视图控制器

// RootViewController.m

- (void)viewDidAppear:(BOOL)animated 
    [super viewDidAppear:animated];

    NSLog(@"Did appear");
    // Do something that I want it to happen only when the application is visible to user

当用户点击应用程序图标时,应用程序会按照我的预期运行。我在控制台中看到“确实出现了”,之后发生的事情就像我预期的那样。

但是当应用程序唤醒执行后台任务(用户不可见)时,RootViewController's viewDidAppear 仍然因为这条线而被调用

[self.window makeKeyAndVisible];

通过调用 makeKeyAndVisible,它使RootViewController 可见,即使它只是在后台任务中唤醒。要解决这个问题,我必须将此行移至applicationDidBecomeActive

- (void)applicationDidBecomeActive:(UIApplication *)application 
    [self.window makeKeyAndVisible];

因此,RootViewController's viewDidAppear 现在仅在应用程序处于前台(用户可见)时被调用。但是,我担心的是,当应用程序在设备内存中(活动或非活动)applicationDidBecomeActive 将被调用多次。

用户启动应用程序 应用程序从跳板再次激活 设备解锁 结束通话

如果我在应用程序生命周期内多次调用UIWindow's makeKeyAndVisible 有什么问题吗?

【问题讨论】:

我认为UIAlertViewUIActionSheet 会调用此方法,因为它们在显示时会更改键窗口。我认为在applicationDidBecomeActive 中调用[self.window makeKeyAndVisible] 不是一个好方法,因为那时可能会有UIAlertView 显示。 @KudoCC 感谢您的信息,我以前从不知道这个!你知道如果我显示警报视图 --> 锁定设备 --> 解锁它 --> 调用 [self.window makeKeyAndVisible] 会发生什么吗? 不好说,是个未定义的动作,你可以试一试。 【参考方案1】:

您可以轻松确保 makeKeyAndVisible 只发生一次:将其包装起来。

if (!self.window.keyWindow) 
    [self.window makeKeyAndVisible;
 else if (self.window.hidden) 
    self.window.hidden = NO;

【讨论】:

感谢您的解决方案 Henri,我确实应用了与您的答案类似的东西。顺便问一下,你知道如果我多次调用 makeKeyAndVisible 会发生什么吗? (就像 KudoCC 在我原来的问题中的评论一样,他说 UIAlertView 和 UIActionSheet 也确实调用了 makeKeyAndVisible) 我认为这取决于上下文。连续调用它两次,它可能不会做任何事情。我现在不在办公桌前,但很容易检查。无论如何,我更喜欢确保我自己需要它,而不依赖于 API 逻辑内部。因此简单的换行。

以上是关于UIWindow 的 makeKeyAndVisible 和后台任务的主要内容,如果未能解决你的问题,请参考以下文章

iOS小技能:特殊的UIView(UIWindow)

86UIWindow简单介绍

UIWindow 的目的是啥?

walker代理深入浅出——程序的启动原理(下)(探究 UIWindow)

在主窗口上创建一个新的 UIWindow

iPhone - UIWindow 根据当前方向旋转?