Jakub Truhlář
Jakub Truhlář

Reputation: 20720

Protocol methods in a class extension are not called under specific conditions

I encountered a weird behavior. The best way I can put it is … Not overridden protocol methods in a class extension are not called while the superclass already conforms to the protocol (via extension). However this happens only while it's build with the release build configuration.

class A: UIViewController {}

extension A: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("scrollViewDidScroll in superclass")
    }
}

class B: A {
    // A tableView (and its data source and delegate) is set here…
}

extension B: UITableViewDelegate {
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        super.scrollViewDidScroll(scrollView)
        print("scrollViewDidScroll in subclass")
    }

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        print("scrollViewDidEndDragging")
    }
}

The output:

scrollViewDidScroll in superclass

scrollViewDidScroll in subclass

scrollViewDidEndDragging

however if I build it with the release build configuration, the output is

scrollViewDidScroll in superclass

scrollViewDidScroll in subclass

I can solve the problem if I don't use the extension for protocol conformance approach in the class B and just use the regular way instead (put the methods that implement a protocol into the class).

The question is … how come?

Upvotes: 1

Views: 296

Answers (1)

Ravi Kant Bagoria
Ravi Kant Bagoria

Reputation: 69

I too encountered the same behaviour.

Xcode version - 12.4 Swift version - 4.2

I also encounter that this behaviour is shown only when applicationDidBecomeActive method is called in the application.(Mostly when you have navigation to some other Screen like authentication etc)

Fix: You need to assign the ViewController as delegate again.

func applicationDidBecomeActive(_ application: UIApplication) {

    fixesForCallBackInExt()
}

func fixesForCallBackInExt() {
    guard  let navController = window?.rootViewController as? UINavigationController else { return }
    if let tabVC = navController.topViewController as? UITabBarController, let topVC = tabVC.selectedViewController, topVC.isKind(of: UIViewController.self) {
        // Set Your Delegate = topVC
    } else if let topVC = navController.topViewController, topVC.isKind(of: UIViewController.self) {
        // Set Your Delegate = topVC
    }
}

Upvotes: 0

Related Questions