如何从我的appDelegate中访问我的viewController?iOS

66

我有一个iOS应用程序,我在xCode中创建了一个“基于视图”的应用程序。我只有一个viewController,但它会自动显示,并且我看不到任何将其与我的appDelegate联系起来的代码。我需要从我的appDelegate传递数据到我的viewController,但不知道如何实现。

我的appDelegate.h:

#import <UIKit/UIKit.h>


@interface AppDelegate : UIResponder <UIApplicationDelegate>

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

@end

此外,appDidFinishLoadingWithOptions:

- (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;
}
6个回答

107

您可以使用以下方式访问它:

MyViewController* mainController = (MyViewController*)  self.window.rootViewController;

如果你将视图嵌套在TabViewController或Navigation Controller中,那么它会返回给你该控制器,并且你需要访问其中的视图控制器。


2
抱歉,在这个上下文中,“self”指什么?你是在指UIApplicationDelegate中的“-window”属性吗?如果是的话,那只适用于iOS 5+ - 提醒一下。 - Conrad Shultz
@ConradShultz 是的,那是UIApplicationDelegate。这很重要,谢谢! - utahwithak
我不确定这是最好的或唯一的方法,但这是我选择的方式,它可以正常工作。谢谢。 - HackyStack
如果我想访问的视图控制器是我从根视图控制器呈现的视图控制器,我该怎么办?我是通过Storyboard中的标识符进行呈现的。我该如何访问它? - Suraj K Thomas
我应该如何在使用Objective C的iOS 11中声明,以避免出现错误? - iOS Developer

22
如何使用传统的NSNotifications在应用委托中发送消息给任何监听者(例如您的视图控制器),以便更新内容?或者,您可以使用Key Value Observing来让您的视图控制器观察应用委托中的某些属性。请参考:NSNotificationsKey Value Observing

@jmstone - 将根视图控制器设置为应用程序委托的代理?从概念上讲,这似乎是可能的,但对于新手Objective C人员来说,这似乎可能会令人困惑。 - Michael Dautermann
问题在于ViewController.h和ViewController.m是由xCode创建的,还有我的AppDelegate.m和.h。在我的AppDelegate中没有任何地方创建我的ViewController实例,也没有将其设置为rootViewController或其他任何内容...这是我的AppDelegate.h,它只有window: - HackyStack
我仍然认为我的解决方案是最好的。;-) - Michael Dautermann
@jmstone - 这并不是一个属性,我需要将其变成一个属性。当你创建基于视图的应用程序时,xCode会自动创建AppDelegate、ViewController和"MainStoryboard_Ipad.storyboard",并将它们连接起来,但我无法在代码中找到任何"连接"的问题所在... - HackyStack
如果我想访问的视图控制器是我从根视图控制器呈现的视图控制器,我该怎么办?我是通过Storyboard中的标识符进行呈现的。我该如何访问它? - Suraj K Thomas
显示剩余6条评论

12

由于您只有一个视图控制器,这是一种通用的方法(与应用程序如何设置无关):

UIViewController *vc = [[[UIApplication sharedApplication] keyWindow] rootViewController];

9
如果您想获取除根视图控制器之外的任何其他UIViewController
UIWindow *window=[UIApplication sharedApplication].keyWindow;
UIViewController *root = [window rootViewController];

UIStoryboard *storyboard = root.storyboard;
CustomViewController *vcc =(CustomViewController *) [storyboard instantiateViewControllerWithIdentifier:@"storyBoardID"];

很高兴看到我的回答对你有所帮助 @JenyaKyrmyza :) - Arben Pnishi

6

一种快速的方法,您可以从任何地方调用它,而不仅仅是从appdelegate:

/// EZSwiftExtensions - Gives you the VC on top so you can easily push your popups
public var topMostVC: UIViewController? {
    var presentedVC = UIApplication.sharedApplication().keyWindow?.rootViewController
    while let pVC = presentedVC?.presentedViewController {
        presentedVC = pVC
    }

    if presentedVC == nil {
        print("EZSwiftExtensions Error: You don't have any views set. You may be calling them in viewDidLoad. Try viewDidAppear instead.")
    }
    return presentedVC
}

这是一个标准函数,已经包含在以下项目中:

https://github.com/goktugyil/EZSwiftExtensions


1
到目前为止,这似乎是最好的答案。 - ScottyBlades

0
如果你使用了"基于视图的应用程序"模板,单个视图控制器应该可以通过你的应用委托中的属性访问。它是相同的视图控制器,被设置为导航控制器的根视图控制器。
如果由于某种原因您的项目设置不同,您可以获取窗口的根视图控制器(应该是导航控制器),然后获取其顶部视图控制器。

编辑: 问题是这样的:在iOS5和storyboard中,Apple已经抽象化了你过去可以访问到的很多初始设置(如果你选择退出storyboards,仍然可以访问)他们改变了传递给main()的参数,并在storyboard中执行更多的设置(实际上只是一个nib文件)。我认为,这部分是为了防止人们在AppDelegate中负载过重,就像你现在所做的那样。实质上,AppDelegate存在是为了管理应用程序的生命周期。它并不真正意味着执行方法来传递信息给您的视图控制器。从本质上讲,您的视图控制器负责提供数据的重活。我建议将代码移入视图控制器中,可能在viewDidLoad中。如果您需要知道launchOptions objectForKey测试的结果,则可以在AppDelegate上创建一个属性,比如BOOL launchOptionsURLKeyExists,并适当地设置它。然后在您的视图控制器中只需获取此属性的值即可。您的AppDelegate已经是单例模式,因此可以通过[UIApplication sharedApplication].delegate访问它

编辑2:当视图添加到UIApplicationDidEnterForegroundNotification通知中时,viewWillAppear/viewDidAppear将被调用,在您的视图控制器中响应该消息。


这里没有属性,我不知道它在哪里设置的,这就是我在这里说的...它在哪里设置的???这是我的appDelegate.h文件:#import <UIKit/UIKit.h> - HackyStack
我已经编辑了我的回复。我从不使用Storyboards,所以我忘记它们现在抽象了很多这些东西。 - jmstone617
问题在于当应用程序变为活动状态时,我需要拉取新的查询字符串并将其传递给我的视图控制器,但是我知道的唯一一个在应用程序变为活动状态时调用的方法是在应用委托中(willBecomeActive或任何其他方法)。我需要让视图控制器意识到它可能已经变为活动状态,并具有不同的查询字符串... - HackyStack
不是真的。这就是问题所在!ViewWillAppear 是我的控制器中代码获取查询字符串的地方,但当应用程序变为活动状态(在后台运行后)时,它不会被调用,只有在初始启动时才会被调用。请现在使用此线程:http://stackoverflow.com/questions/10017305/viewwillappear-is-not-called-in-my-view-controller-when-the-app-becomes-active - HackyStack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接