Ayoze Roberto Bernardo
Ayoze Roberto Bernardo

Reputation: 286

Clean Swift / VIPER protocol conformance

I am currently working on a Clean Swift (similar to VIPER) implementation. For each module I have a Presenter and a Displayer (which is a ViewControler in the end) all of it based on protocols.

Those are my generic Displayer and Presenter protocols:

// Generic Displayer
protocol BaseDisplayLogic: class {
    func displayError(message: String)
    func displayApiError(error: ApiError)
}

extension BaseDisplayLogic where Self: UIViewController {
    func displayApiError(error: ApiError) {
        if let errorDescription = error.errorDescription {
            self.warningAlert(errorDescription)
        }
    }

    func displayError(message: String) {

    }
}

// Generic Presenter
protocol BasePresentationLogic: class  {

    var viewController: BaseDisplayLogic? { get }


    func presentError(message: String)
    func presentApiError(error: ApiError)

}

extension BasePresentationLogic {


    func presentError(message: String) {

    }

    func presentApiError(error: ApiError) {

    }
}

And here it is the implementation of a module I would need:

// A displayer
protocol RestorePasswordDisplayLogic: BaseDisplayLogic {
    func displayPasswordRestore(ok: Bool)
}

class RestorePasswordViewController: UIViewController {
}


// A presenter
protocol RestorePasswordPresentationLogic: BasePresentationLogic {
    func presentPasswordRestore(ok: Bool)
}

class RestorePasswordPresenter: RestorePasswordPresentationLogic {
    weak var viewController: RestorePasswordDisplayLogic?


    func presentPasswordRestore(ok: Bool) {
        self.viewController?.displayPasswordRestore(ok: ok)
    }

}

The problem is that I am getting an error in the Presenter implementation (RestorePasswordPresenter in this case) because it is not conforming to the BasePresentationLogic protocol. If I remove the

var viewController: BaseDisplayLogic? { get }

it works perfectly, but I need the viewController var to be visible from the BasePresentationLogic extension so I can make a default implementation of the presentError and presentApiError methods.

Any idea on that?

Upvotes: 1

Views: 246

Answers (1)

Rob Napier
Rob Napier

Reputation: 299265

The direct problem is that you're not conforming to the protocol as required. You required a viewController of type BaseDisplayLogic?. So you need to create that, and store your more specific version in a backing variable:

weak var restorePasswordViewController: RestorePasswordDisplayLogic?
var viewController: BaseDisplayLogic? { restorePasswordViewController }

(Personally, and only as an opinion, I think this is wildly overusing protocols, and likely to be a source of many headaches, especially if you ever try to make these pieces generic and start needing type-erasers. If you've been successful with it, more power to you, but maintaining all these parallel class/protocol hierarchies seems a bad idea to me. It's reinventing class inheritance with protocols, which isn't what protocols are for, and they're not very good at it.)

Upvotes: 1

Related Questions