How to tell Swift which function signature to use between default optionals

Viewed 442

I want to instantiate the root view controller of a Storyboard I created.

To do so I was used to calling -instantiateInitialViewController() from a storyboard.

The thing is since iOS13 there’s a new method signature that takes a new optional argument: (creator: ((NSCoder)->ViewController?)?)

Capture of Xcode showing autocompletion

The annoying thing is that Xcode thinks I want to use that new API, which makes my app incompatible with older OS.

Capture of Xcode showing an inline error prompt

And I can’t get around it, even with a version check.

Capture of Xcode still showing an error after applying a suggested fix

My question is: How to tell the compiler to use the method signature without the parameter?

4 Answers

Quick Answer for your issue: Xcode BUG

First of all, as your screenshots show, it's a bug. (try removing driven data or restarting stuff to make it work). The following is the answer to your question.


Explanation: How to tell the compiler to use which method signature

Swift infers the function signature based on the used Types in the expression. So imagine this:

class ViewController { }
class UIViewController { }

func instantiateInitialViewController() -> UIViewController? {}
func instantiateInitialViewController() -> ViewController? {}

So calling this would be ambiguous use of instantiateInitialViewController():

let theController = instantiateInitialViewController()

The solution for this is to tell the compiler what is the expected type explicitly:

let theController: ViewController? = instantiateInitialViewController()
let theOtherController: UIViewController? = instantiateInitialViewController()

The new instantiateInitialViewController return type is a protocol (ViewController) that constrained to UIViewController. So it should infer the type and have no logical difference from the old one. So just keep calm and just let it infer ;)

Ok this became patently a bug from Xcode.

After restarting my mac, it works fine.

Why did I thought the error could came from me… ‍♀️

Thank you all!

Actually, I don't know the answer on your question, but maybe you just want to init your ViewController from Storyboard for iOS version less than 13.0? Try this:

UIStoryboard(name: "storyboardName", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerID")

UIViewController objects can be saved to disk and restored upon request (ie, battery down, memory warning issues).

The new iOS13 method

instantiateInitialViewController { (coder:NSCoder) -> MyViewController? in
    return MyViewController(coder: coder)
}

allows the view controller instance come to life by restoring some of its state.

This method call invokes initWith(coder:) in MyViewController, where one can, in this example, restore "name" property.

class MyViewController: UIViewController {
      
    var name:String?
    
    required init?(coder: NSCoder) {
        name = coder.decodeObject(forKey: "name") as? String
        super.init(coder: coder)
    }   
}

    
Related