iosswift3dtouchquickaction

3D Touch Quick Action For Same ViewController


the entry ViewController for my application consists of two buttons: weight and age. In the main ViewController, this is the code that runs when you click the weight button:

@IBAction func weightSearch(_ sender: Any) {
//Weight button clicked
inputReset()
userInput.keyboardType = UIKeyboardType.numberPad
userInput.becomeFirstResponder()
}

And this is the code that runs when you click the age button:

@IBAction func ageSearch(_ sender: Any) {
    //Age button clicked
    inputReset()
    userInput.inputView = agePicker
    userInput.becomeFirstResponder()
}

What I am trying to do is implement a two 3D Touch quick actions, one called Weight Search (which runs the code for func weightSearch) and the other called Age Search (which runs the code for func ageSearch). Here is what I have done so far:

  1. In the Info.plist file, I have created a UIApplicationShortcutItems array, with two Items of type dictionary, and their respective UIApplicationShortcutItemTitle and UIApplicationShortcutItemType.
  2. In my AppDelegate.swift file, I have added the preliminary quick-action code:

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
    //3D touch features 
    }
    

My issue now is that I am unsure what code to write for my AppDelegate.swift file. All the tutorials I have watched and all the similar questions on this site deal with calling a different ViewController using the quick actions, not calling different functions on the same `ViewController. Thank you in advance.


Solution

  • Because iOS is telling your AppDelegate that a Quick Action was selected by the user, you're free to do what you want with it. To get a reference to your ViewController you can just ask the window for the rootViewController (which will be your ViewController). You're free then to do what you need to.

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
      guard let viewController = window?.rootViewController as? ViewController else { return }
      viewController.performSomeAction()
    }
    

    You could also future proof this a bit and crash when running in debug mode if some point in the future you changed to have a different type of view controller as the root:

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
      guard let viewController = window?.rootViewController as? ViewController else { 
      assertionFailure("Wrong view controller type!") // This only crashes in debug mode
      return 
    }
      viewController.performSomeAction()
    }