SomaMan
SomaMan

Reputation: 4164

Swift - Creating a means to return UIViewControllers which conform to a protocol

I'm trying to write code which returns a viewController, which conforms to a protocol, as determined by the key passed in to the subscript -

struct ViewControllerName {

    // keys -

    static var pushNotification: Identifier<PushNotificationPresenting> { .init(name: "PushNotificationViewController") }
    static var termsAndConditions: Identifier<TermsPresenting> { .init(name: "TermsAndConditionsViewController") }

    // give me the viewController

    static subscript<T>(identifier: Identifier<T>) -> T? {
        get {
            let storyboard = UIStoryboard(name: identifier.name, bundle: nil)
            return storyboard.instantiateViewController(withIdentifier: identifier.name) as? T
        }
    }

    struct Identifier<T> {
        let name: String
    }
}

So this code works, in that it returns an object which conforms to the protocol, but I'd like it to return a UIViewController which conforms, eg -

static subscript<T>(identifier: Identifier<T>) -> (UIViewController & T)? {
    get {
        let storyboard = UIStoryboard(name: identifier.name, bundle: nil)
        return storyboard.instantiateViewController(withIdentifier: identifier.name) as? (UIViewController & T)
    }
}

However, that doesn't compile. Is it even possible? It would be nice to not have to do the 'as? UIViewController' dance in my consuming code. Any thoughts welcome...

Upvotes: 0

Views: 425

Answers (2)

Dhawal
Dhawal

Reputation: 1065

you want to get type UIViewController, this method return UIViewController

static subscript<T>(identifier: Identifier<T>) -> UIViewController? {
    get {
        let storyboard = UIStoryboard(name: identifier.name, bundle: nil)
        return storyboard.instantiateViewController(withIdentifier: identifier.name)
    }
}

Upvotes: 0

andrija
andrija

Reputation: 342

If you want to get a type UIViewController & T, then you should create a new type that subclasses UIViewController and implements T, and just provide that as the generic parameter of your method.

If you don't want to create a new type, then you should extend the UIViewController class so that it conforms to T, and then just provide UIViewController as the generic parameter of your method.

Now, you might be wanting to create a new type somehow 'on the fly', but I think that you cannot do that. You have to explicitly declare it. Therefore I think the first solution I provided is the one you might be looking for.

Upvotes: 2

Related Questions