当应用程序处于活动状态时,不会在我的视图控制器中调用 viewWillAppear

Posted

技术标签:

【中文标题】当应用程序处于活动状态时,不会在我的视图控制器中调用 viewWillAppear【英文标题】:viewWillAppear is not called in my view controller when the app becomes active 【发布时间】:2012-04-04 18:40:14 【问题描述】:

免责声明:我是 ios 新手。

我使用 Xcode 的模板创建了一个基于视图的应用程序,可以将图片上传到网站。 Xcode 自动为我创建了 AppDelegate.m (& .h) 和 ViewController.m 以及一个故事板。该应用程序是从使用 URL 架构的网站启动的,我在视图控制器中使用该信息。我有两个问题:

1) 这是将查询字符串从我的 AppDelegate 传递到视图控制器的好方法吗? 我的 AppDelegate 中有一个名为 queryStrings 的 NSDictionary 属性,用于存储查询字符串。然后在我的视图控制器中的 viewWillAppear 中,我使用以下代码来访问它:

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSDictionary *queryStrings = appDelegate.queryStrings;
    wtID = [queryStrings valueForKey:@"wtID"];

2) 当应用程序已经启动但在后台并且用户通过网页上的 url 再次打开应用程序(使用不同的查询字符串)时,我在 AppDelegate 中实现了 openURL,它在 AppDelegate 中填充了我的 queryStrings 属性。问题是:视图控制器的 viewWillAppear 方法永远不会被调用,所以上面的代码不会被执行。如何将查询字符串数据获取到视图控制器?视图控制器如何知道应用程序刚刚激活?

注意:因为项目是使用 Xcode 中的“基于视图的应用程序”模板创建的,所以我的 AppDelegate 拥有的唯一属性是 window 属性。我不知道 AppDelegate 甚至在代码中的哪个位置引用了我的视图控制器......它从来没有设置为 rootViewController 或代码中的任何东西......我想这只是我看不到的一些 IB 魔法.

如果有帮助,这是我的 AppDelegate.h:

#import <UIKit/UIKit.h>


@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSDictionary *queryStrings;

@end

这是我的 didFinishLoadingWithOptions、openURL 和我的辅助方法:parseQueryString:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    // Override point for customization after application launch.
    [[JMC sharedInstance] configureJiraConnect:@"https://cmsmech.atlassian.net/"           projectKey:@"WTUPLOAD" apiKey:@"7fc060e1-a795-4135-89c6-a7e8e64c4b13"];

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsURLKey] != nil) 
        NSURL *url = [launchOptions objectForKey: UIApplicationLaunchOptionsURLKey];
        NSLog(@"url received: %@", url);
        NSLog(@"query string: %@", [url query]);
        NSLog(@"host: %@", [url host]);
        NSLog(@"url path: %@", [url path]);
        queryStrings = [self parseQueryString:[url query]];
        NSLog(@"query dictionary: %@", queryStrings);
    
    else 
        queryStrings = [self parseQueryString:@"wtID=nil"];
    

    return YES;



-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation

    NSLog(@"openURL executed");
    if (!url) 
        return NO;
    NSLog(@"query string: %@", [url query]);
    queryStrings = [self parseQueryString:[url query]];

    mainViewController.wtID = [queryStrings valueForKey:@"wtID"];
    return YES;


-(NSDictionary *)parseQueryString:(NSString *)query

    NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:6];
    NSArray *pairs = [query componentsSeparatedByString:@"&"];
    for (NSString *pair in pairs)
    
        NSArray *elements = [pair componentsSeparatedByString:@"="];
        NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        [dictionary setObject:val forKey:key];
    
    return dictionary;

提前致谢!

【问题讨论】:

For 2: 你能把代码放到applicationWillEnterForeground吗? 没有问题的代码是在控制器而不是应用程序委托... 【参考方案1】:

所以,故事板开始让我感到紧张,我什至没有构建你的应用程序! :)

正如我在您的另一个问题中所述(这是重复的,但是嘿),缺少对视图控制器的引用是由于情节提要。 viewDidAppear 和 viewWillAppear 在视图添加到层​​次结构时被调用。往返于背景和前景并不符合添加到层次结构的条件。幸运的是,您的应用会发送与 AppDelegate 中的方法相对应的通知。只需注册为 UIApplicationWillEnterForegroundNotification 通知的观察者。然后,您可以在收到通知后触发的方法中更新您的 UI!

编辑: 将链接添加到重复的问题中以获得良好的衡量标准:How do I access my viewController from my appDelegate? iOS

【讨论】:

为了记录,我在这篇文章中问了两个密切相关的问题。其中一个与我在另一篇文章中提出的类似,但我在这篇文章中对其进行了重新组合,以更具体地说明问题所在。感谢您的 cmets 并尝试做出贡献!不幸的是,没有人有一个很好的答案...... 这个问题的答案(为什么 viewWillAppear 在从后台返回时不会被调用)已经得到解答。当您从后台返回时,如何获得更改通知还有一个答案。让我知道我是否可以在这里更清楚地回答。【参考方案2】:

嗯,那为什么你的AppDelegate 中没有声明UIViewController

更新

当你创建一个新项目时,你的AppDelegate 中应该有这样的东西:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIViewController *viewController;

@end

//

#import "ViewController.h"

@implementation AppDelegate

@synthesize window, viewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.viewController = [[ViewController alloc] init];

    [self.window setRootViewController:self.viewController];
    [self.window makeKeyAndVisible];

    return YES;


//...

@end

【讨论】:

这是我的问题!我知道这是因为我在 Xcode 中创建项目时使用了“基于视图的应用程序”模板,我相信它是在幕后连接起来的,当我现在尝试从应用委托。你几乎总结了我的整个问题...... 使用 Storyboards 设置新项目不会在应用程序委托中为您提供 UIViewController。正如我在@HackyStack 开始的问题中解释的那样,它在情节提要的卸载过程中处理所有这些设置。 好的,但现在我被一个 99% 功能齐全的应用程序困住了,它有一个故事板。我需要访问视图控制器,因此当应用程序变为活动状态(由带有新查询字符串的 URL 启动)并且在我的应用程序委托中调用 openURL 时,我需要告诉视图控制器查询字符串已更改... 没有。那肯定不存在,jmstone 已经说过,我同意这是因为它使用了我开始想要称之为“那个愚蠢的故事板”的东西......所以现在我们知道它没有添加那个代码...... . 我该怎么办?我应该手动将上面的代码添加到我的 appDelegate 吗?添加vc属性?这会导致两种情况吗?一个是我明确创建的,一个是在故事板幕后创建的 IB?这是废话!隐藏定义 rootViewController 的代码是 CRAP! 老实说,我以前从未使用过故事板。上面的代码,我在每个项目中都有,一直有效。

以上是关于当应用程序处于活动状态时,不会在我的视图控制器中调用 viewWillAppear的主要内容,如果未能解决你的问题,请参考以下文章

当搜索栏处于活动状态时,快速表视图被锁定

在键盘处于活动状态时呈现模态视图控制器

如何确定当前视图控制器是不是处于活动状态,如果处于活动状态则执行代码

当 UIAlertController 处于活动状态时,VoiceOver Z 手势不会触发

当 UISearchController 处于活动状态时呈现 UIAlertController

从 UIViewController 切换到另一个时如何保持 UILongPressGestureRecognizer 处于活动状态