如何从iOS AppDelegate调用视图控制器函数?

我正在接收来自远程推送通知的呼叫,其中包含要显示的图像的path。

AppDelegate是:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { // get url from notification payload (shortened version) let url = alert["imgurl"] as? NSString let vc = ViewController() vc.loadImage(url as String) // cannot find the imageView inside } 

…视图看起来像这样:

 func loadImage(url:String) { downloadImage(url, imgView: self.poolImage) } // http://stackoverflow.com/a/28942299/1011227 func getDataFromUrl(url:String, completion: ((data: NSData?) -> Void)) { NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) { (data, response, error) in completion(data: NSData(data: data!)) }.resume() } func downloadImage(url:String, imgView:UIImageView){ getDataFromUrl(url) { data in dispatch_async(dispatch_get_main_queue()) { imgView.image = UIImage(data: data!) } } } 

我得到一个exception,说imgView是空的(它被声明为@IBOutlet weak var poolImage: UIImageView!我可以通过调用loadImage("http://lorempixel.com/400/200/")来显示图像button点击。

我在stackoverflow上find了几个相关的答案(一个是上面引用的),但都没有工作。

如果你想以模态方式显示一个新的视图控制器,那么请进一步查看rach的答案。

如果你的ViewController已经在屏幕上,你将需要更新它来显示你需要的信息。

你如何做到这一点将取决于你的根视图控制器设置。 你的视图控制器embedded在UINavigationController中吗? 如果是的话试试这个:

 func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { if let rootViewController = window?.rootViewController as? UINavigationController { if let viewController = rootViewController.viewControllers.first as? ViewController { let url = alert["imgurl"] as? NSString viewController.loadImage(url as String) } } } 

如果不是,那么试试这个:

 func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { if let rootViewController = window?.rootViewController as? ViewController { let url = alert["imgurl"] as? NSString rootViewController.loadImage(url as String) } } 

通过调用@IBOutlet weak var poolImage: UIImageView! 你将poolImage的初始化poolImage给故事板。 由于你正在初始化视图控制器let vc = ViewController()vc会知道,因为你在类中声明它,所以期望有一个对poolImage的引用,但是因为你实际上没有初始化vc的视图和子视图)在加载UI之前, poolImage保持零。

如果您需要在vc初始化时引用UIImageView ,则必须手动实例化它: let poolImage = UIImageView()

编辑:你的ViewController实现的poolImage目前看起来像这样:

 class ViewController : UIViewController { @IBOutlet weak var poolImage : UIImageView! // rest of file } 

要通过let vc = ViewController()AppDelegate访问poolImage ,必须使实现如下所示:

 class ViewController : UIViewController { /* ---EDIT--- add a placeholder where you would like poolImage to be displayed in the storyboard */ @IBOutlet weak var poolImagePlaceholder : UIView! var poolImage = UIImageView() // rest of file override func viewDidLoad() { super.viewDidLoad() /* ---EDIT--- make poolImage's frame identical to the placeholder view's frame */ poolImage.frame = poolImagePlaceholder.frame poolImagePlaceholder.addSubView(poolImage) // then add auto layout constraints on poolImage here if necessary } } 

这样,当创buildViewController时, poolImage可供参考。

我相信在你打电话的时候

 let vc = ViewController() 

它还没有被实例化。 既然你正在为你的UIImageView使用@IBOutlet,我假设你实际上有UIViewController。

也许这可以通过这个纠正:

 let vc = self.storyboard?.self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerStoryboardID") vc.loadImage("imageUrl") self.presentViewController(vc!, animated: true, completion: nil) 

让我知道如果它的作品。 🙂

编辑:你可以通过这个方法调用storyboard的一个实例:

 self.window = UIWindow(frame: UIScreen.mainScreen().bounds) var storyboard = UIStoryboard(name: "Main", bundle: nil) var vc = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! UIViewController vc.loadImage("imageUrl") self.window?.rootViewController = vc self.window?.makeKeyAndVisible() 

我认为的原因是因为imageView可能没有被initialized 。 尝试以下解决scheme。

添加另一个init方法到你的viewController接受一个URLString 。 一旦你收到push notificationinitialize你的viewController并将imageURL传递给新的init方法。

在新的initMethod ,你可以使用imageURL来下载图像并将其设置为imageView 。 现在你的imageView不应该是null ,错误不应该发生。