-3

I do have a similar problem as protocol extension, does not conform to protocol, but the solution there does not work for me and I can not figure out why.

I want to create a protocol with an extension to handle the login behaviour of my app.

First of all I am not sure if I should put the protocol with its extension in a separate file or just in the AppDelegate above the class declaration. Both ways do not work. The AppDelegate knows the protocol, but it does not know the extension, so it wants me to implement handleLogin() in the class.

Protocol

protocol LoginFlowHandler {
    func handleLogin()
}

Protocol Extension

public extension LoginFlowHandler {

    func handleLogin(withWindow window: UIWindow?) {

        // Just for testing purpose
        let userIsLoggedIn = false

        if userIsLoggedIn == true {
            self.showMainApp(withWindow: window)
        } else {
            self.showLogin(withWindow: window)
        }

    }

    func showLogin(withWindow window: UIWindow?) {
        window?.subviews.forEach { $0.removeFromSuperview() }
        window?.rootViewController = nil
        window?.rootViewController = UIStoryboard(name: "Login", bundle: nil).instantiateInitialViewController()
        window?.makeKeyAndVisible()
    }

    func showMainApp(withWindow window: UIWindow?) {
        window?.rootViewController = nil
        window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
        window?.makeKeyAndVisible()
    }
}

AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate, LoginFlowHandler {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow.init(frame: UIScreen.main.bounds)

        handleLogin(withWindow: window)
        return true
    }
}

Thank you in advance!

matt
  • 515,959
  • 87
  • 875
  • 1,141
psteinroe
  • 493
  • 1
  • 6
  • 18
  • 1
    You haven't explained what the problem is. What's going wrong? – matt Sep 12 '17 at 21:57
  • 1
    `LoginFlowHandler` does not know any window variable. Is there any reason to define it as a protocol and not as methods in the AppDelegate? – hfehrmann Sep 12 '17 at 22:05
  • "First of all I am not sure if I should put the protocol with its extension in a separate file or just in the AppDelegate above the class declaration." Either way works. It doesn't matter technically. Use whichever approach makes your code best organized. Personally, if it's a protocol for a delegate of particular class, I put it in the file with that class. If it's a more general protocol, I put it in a separate file. It depends upon the intent. But this raises the question as to why this is a protocol at all. – Rob Sep 12 '17 at 22:06
  • I don't know what "does not know any window variable" means. – matt Sep 12 '17 at 22:07
  • 4
    Your protocol defines a required function `handleLogin()` but neither your App Delegate nor your extension implements that function. – Paulw11 Sep 12 '17 at 22:07
  • @Paulw11 exactly so – matt Sep 12 '17 at 22:08
  • 2
    Your method signature for `handleLogin` in the protocol declaration (which currently says it takes no parameters) needs to match your implementation (which does take a parameter). – Rob Sep 12 '17 at 22:09

2 Answers2

3

It is because your protocol has no parameters and its implementation has.

Protocol:

handleLogin()

Implementation:

handleLogin(withWindow window: UIWindow?)

If you remove the parameter from extension or add the parameter in the protocol it will work.

valdeci
  • 13,962
  • 6
  • 55
  • 80
1

it wants me to implement handleLogin() in the class.

Yes, because that's what you told it to do. That's what it means when you say

protocol LoginFlowHandler {
    func handleLogin()
}

and then declare your class as an adopter of LoginFlowHandler:

class AppDelegate: UIResponder, UIApplicationDelegate, LoginFlowHandler {

That means that this class must have an implementation of handleLogin(). It doesn't.

Your code compiles fine for me if you just remove the requirement from the protocol:

protocol LoginFlowHandler {
    //func handleLogin()
}

It's unclear what you thought you were accomplishing with that requirement, so there's no harm done by removing it.

Or, if you insist on having the requirement for some reason, then write it like this:

protocol LoginFlowHandler {
    func handleLogin(withWindow:UIWindow?)
}

That way, the requirement is satisfied by the protocol extension you wrote.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I suspect you know this, but for the benefit of future readers, a (poorly documented, IMHO) reason to declare `handleLogin` as a requirement of the protocol is so that it will employ dynamic dispatch. If not declared as part of the protocol, the method will use static dispatch. This would appear to be moot in the case of the OPs question, but it factors into the question whether the method implemented in a protocol extension should also be declared as protocol requirement, too. – Rob Sep 12 '17 at 22:52
  • 1
    @Rob I do know that, but the question doesn't seem to involve it. The OP seems merely to want to know why the code isn't compiling. – matt Sep 12 '17 at 22:56