Roi Mulia
Roi Mulia

Reputation: 5896

Workaround for simple protocol inheriting conformance

In our app, we have a service that helps us decide which Modal UIVIewController should we present next. Every ModalVIewController has common function such as dismiss() but also a specific function it implements. So that's what we tried:

The base protocol that is common to all VC's base functions.

protocol ModalScreenDelegate: AnyObject {
    func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
}

A base protocol that every UIViewController implements

protocol ModalScreen: UIViewController {
    var delegate: ModalScreenDelegate? { get set }
}

Now we create a protocol with specific-implementation of ModalScreenDelegate base protocol like so:

protocol ShareToFacebookDelegate: ModalScreenDelegate {
    func someCustomMethod()
}

And assign it to:

class ShareToFacebookViewController: UIViewController, ModalScreen {
   weak var delegate: ModalScreenDelegate? // **WORKS**
   weak var delegate: ShareToFacebookDelegate? // **DOESN'T WORKS**
}

If I'm trying to use ShareToFacebookDelegate to instead of ModalScreenDelegate the compiler throws an IDE error saying I have to change it back to ModalScreenDelegate.

Why wouldn't it work? It's ShareToFacebookDelegate conforms to ModalScreenDelegate. Any help would be highly appreciated. Thank you!

UPDATE Based on Alexandr Kolesnik:

Your method works. But when I try to "fetch" the correct VC within the service under one method like so:

func fetchModal<T: ModalScreen & UIViewController>() -> T? {
    return AddInstagramViewController.create() as? T
}

And then have a coordinator that wants to get this vc:

guard let currentModalViewController vc = modalScreenSupplierService.fetchModal() else {
    return
}

I'm getting:

Generic parameter 'T' could not be inferred

And I can't really say what T will be, all I know that it's going to conform to UIViewController & ModalScreen. Is it solvable?

Upvotes: 1

Views: 78

Answers (2)

Alexandr Kolesnik
Alexandr Kolesnik

Reputation: 2204

If I understood you correctly you can use generic types to manage the problem. Look through the code below. Hope it helps

    protocol ModalScreenDelegate: AnyObject {

    typealias T = ModalScreenDelegate

    func modalScreenWantsToDissmiss(_ modalScreen: T)
}

protocol ShareToFacebookDelegate: ModalScreenDelegate {
    func someCustomMethod()
}

protocol ModalScreen: UIViewController {

    associatedtype T

    var delegate: T? { get set }
}


class ShareToFacebookViewController: UIViewController, ModalScreen {

    typealias T = ShareToFacebookDelegate

    weak var delegate: T?

    override func viewDidLoad() {
        super.viewDidLoad()
        delegate?.someCustomMethod()
    }

}

UPDATE:

    class AddInstagramViewController: SuperVC {

    typealias T = ShareToFacebookDelegate

    private var instaDelegate: ShareToFacebookDelegate?

    override var delegate: ModalScreenDelegate? {
        set {
            instaDelegate = newValue as? ShareToFacebookDelegate
        }
        get {
            return instaDelegate
        }
    }

    static func create() -> AddInstagramViewController {
        return AddInstagramViewController()
    }

}

class SuperVC: UIViewController, ModalScreen {

    typealias T = ModalScreenDelegate

    var delegate: T?

}

class Supplier {

    func fetchModal<M: ModalScreen>() -> M? { return AddInstagramViewController.create() as? M }

}

class SupplierImpl {

    let modalScreenSupplierService: Supplier? = nil

    func goto() {
        guard
            let vc: SuperVC = modalScreenSupplierService?.fetchModal()
        else {
            return
        }
    }

}

Upvotes: 1

Vyacheslav
Vyacheslav

Reputation: 27211

This solution:

   protocol ModalScreenDelegate: AnyObject {
        func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
    }
    protocol ModalScreen: UIViewController {
        var delegate: (ModalScreenDelegate & ShareToFacebookDelegate)? { get set }
    }
    protocol ShareToFacebookDelegate: ModalScreenDelegate {
        func someCustomMethod()
    }
    class ShareToFacebookViewController: UIViewController, ModalScreen {
       weak var delegate: (ModalScreenDelegate & ShareToFacebookDelegate)? 
    }

or inheritance:

protocol ModalScreenDelegate: AnyObject {
    func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
}
protocol ModalScreen: ShareToFacebookDelegate where Self: UIViewController {
    var delegate: ModalScreenDelegate? { get set }
}
protocol ShareToFacebookDelegate: ModalScreenDelegate {
    func someCustomMethod()
}
class ShareToFacebookViewController: UIViewController, ModalScreen {
    func someCustomMethod() {

    }

    func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen) {

    }

   weak var delegate: ModalScreenDelegate? // **WORKS**
}

Upvotes: 1

Related Questions