Is it possible to run a View Controller method within the AppDelegate?

Is it possible to run a View Controller method within the App Delegate?


I am trying to make a static Quick Action that runs a View Controller Method whose purpose is to perform mathematical calculations, and output the results onto UILabels. In other words the Quick Action takes the place of user input and automatically passes a value to the View Controller method, which in turn updates corresponding Labels in the UI.


It's a single view application.


Over at stackoverflow I found a solution that allows me to get apparently verify that the current view is of the proper class and then creates an instance of that class. Xcode throws an exception when running the function: unexpectedly found nil while unwrapping an Optional value.


Here's slightly a slightly edited version of that code:

if let view = self.window {
     vc = view.rootViewController!
     if(vc is ViewController){
          let storyboard = UIStoryboard(name: "Main", bundle: nil)
          let viewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController;
          viewController.calculate("5");
          print("Method Done!")
     }
}

And here's the method it's trying to access in View Controller:

func calculations(input: String){
     inputTextField.text! = "#" +input;
     Labe1l.text = printResult1(Double(input)!);
     Label2.text = printResult2(Double(input)!);
     Label3.text = printResult3(Double(input)!);
     Label4.text = printResult4(Double(input)!);
     Label5.text = printResult5(Double(input)!);
     Label6.text = printResult6(Double(input)!);
 }

So I'm guessing that either: A) What I'm hoping for isn't possible or B) I have no idea what I'm doing

My guess is the problem is the first line of the calculations function. When you assign a value to an optional variable, you do not force unwrap the variable on the left side of the assignment statement. Try just:

inputTextField.text = "#" + input;

Also, you have "Labe1l.text" instead of "Label1.text", and Swift doesn't require ";" at the end of lines.

Note that Double(input)! could also give the unwrapping nil error if the function is passed a string that is not a number. In your simple example, you know you are passing a "5", so it isn't a problem. But for future safety you may want to wrap the LabelN assignments in an if..let:

func calculations(input: String){
     inputTextField.text = "#" + input
    if let d = Double(input) {
         Label1.text = printResult1(d)
         Label2.text = printResult2(d)
         Label3.text = printResult3(d)
         Label4.text = printResult4(d)
         Label5.text = printResult5(d)
         Label6.text = printResult6(d)
    }
}

Depending on your requirements, you could add an else to the if..let and put an error message in each of your Labels (or just set them to an empty string).

Accepted Answer

You are creating a new instance of the view controller and not displaying it. Therefore its view isn't loaded and its outlets aren't filled in. I'm assuming inputTextField is an outlet.


If 'vc' is a ViewController, why not use it instead of creating a new object?

Because when I do:

vc.calculations("10.00")

Instead of creating a new instance, I get this: Value of type 'UIViewController' has no member 'calculations'

Unfortunately removing the force unwrap and adding the if let didn't help. I'm still getting the same error message.


Update: So properly presenting the view was what solved the 'nil' errors.

Try to cast it as a ViewController if that's what it really is. That should make the compiler happy.

Also, I added the following line bellow the instantiation:

window!.rootViewController?.presentViewController(viewController, animated: false, completion: nil)

And now the quick action loads properly the first time but after, it doesn't update again. So for example let's say I enter the number "12" when I manually input the number. When I access a quick action that automatically puts the number "34", it runs fine since it's the first time I use the quick action, but if I were to manually input a number again, and then access the quick action, the view will not run the quick action function, and it'll keep the previous manually inputted number.

Stupid question I know, but I'm new to Swift, how would you cast vc as a ViewController? My guess is:

vc = UIViewController() as ViewController;


that's because I previosuly declared vc to be of type UIViewController right before the switch statement I first posted:


var vc = UIViewController();


By the way, thanks so much for your help!

Never mind! I figured it out, or at least, I found a solution to all my problems! Here's the final code, feel free to let me know if there is/are more proper/ efficient way(s) to do this:

var vc = UIViewController();
     switch (shortCutType) {
      case ShortcutIdentifier.First.type:
          if let view = self.window {
               vc = view.rootViewController!
               if(vc is ViewController){
                    var test123  = vc as! ViewController;
                    test123.calculations("10")
               }
          }
     ......
     }
Is it possible to run a View Controller method within the AppDelegate?
 
 
Q