2

I want to change my ViewController's background color. Within the view controller, I can write self.view.backgroundColor = UIColor (red: 0, green: 0.0, blue: 0.5, alpha: 1.0). However, I need to change it from AppDelegate. According to this answer, accessing properties of the ViewController in AppDelegate works like this:

1) Setting a global variable: var myViewController: ViewController!

2)

var theViewController = ViewController()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.myViewController = theViewController

So that

self.myViewController.view.backgroundColor = UIColor (red: 0, green: 1.0, blue: 0.5, alpha: 1.0)

should change the background color. However, it doesn't. How can I change the ViewController's background color from AppDelegate?

black
  • 1,151
  • 3
  • 18
  • 46
  • You never added your view controller view to your view controller view hierarchy. – Ron May 10 '18 at 17:30

2 Answers2

2

You are creating a new instance of the view controller with var theViewController = ViewController(), and you store the new instance in the global variable you set up, but that instance is never used anywhere.

What you want is the view controller instance used by the app. I'm not sure how you app view hierarchy is set up, but you probably want to get the root view controller for you app.

In the AppDelegate class you can try

theViewController = self.window?.rootViewController
theViewController.view.backgroundColor = UIColor (red: 0, green: 1.0, blue: 0.5, alpha: 1.0)
jimmyg
  • 580
  • 4
  • 13
  • If I try to access another function in my view controller that I defined by `public func foo(){...}` and call it in AppDelegate using `theViewController!.foo()`, I get an error "Value of type 'UIViewController' has no member 'foo'". I guess this is because my defined function is only defined for this specific view controller, not as a general ViewController member function. Is there a way to call the function using that approach? – black May 10 '18 at 19:49
  • 1
    To call a function foo(), that is specific to the view controllers class, you need to cast the view controller. Declare theViewController to be of the type of class that it actually is: `theViewController: MyViewController?`, then assign it with a cast: `theViewController = self.window?.rootViewController as? MyViewController`. – jimmyg May 10 '18 at 21:13
0

You can try , say if your root is a navigationController

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    // wait until vc is displayed

    DispatchQueue.main.asyncAfter(deadline: .now() + 4) {

        if let vv = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {

            vv.viewControllers.last?.view.backgroundColor = UIColor.blue
        }
    }

    return true
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • This answer is a little more thorough than mine--especially considering the navigation controller. If you need to change the color at different times during the life cycle of your app, you would still need your global variable so you can change it later. `var theViewController = vv`. Another option: rather than the `asyncAfter`, you could create a function on the app delegate that you call when the time comes to change the color. That function checks `theViewController` for nil. If nil, then set it by calling the code inside the closure in Sh_khan's code. – jimmyg May 10 '18 at 17:47
  • @jimmyg for sure I'm providing DispatchAfter for illustrating purpose , i don't think there is a need to create a global vc to set it when presenting and check it when we want to change color of topVc ,, easily if the OP has a straight-forward structure he can get it with code sure the root may be navigatio, tabBar , or VC it's the OP responsibility to handle that – Shehata Gamal May 10 '18 at 17:54