Created
January 11, 2019 12:57
-
-
Save ole/9218fa76ba0ffad676636168b815924a to your computer and use it in GitHub Desktop.
Overriding at-objc methods defined in extensions without the dynamic keyword
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Paste this into an iOS playground in Xcode and run | |
// Expected output: | |
// ParentVC: handled in ParentCoordinator | |
// ChildVC: handled in ChildCoordinator | |
// UIViewController: accountLogin() not handled | |
import UIKit | |
NSSetUncaughtExceptionHandler { exception in | |
print("Exception: \(exception.name) — \(exception)") | |
print("Call stack:\n\(exception.callStackSymbols.joined(separator: "\n"))") | |
} | |
extension UIResponder { | |
@objc var coordinatingResponder: UIResponder? { | |
return next | |
} | |
@objc /* no dynamic */ func accountLogin() -> String { | |
return coordinatingResponder?.accountLogin() ?? "\(#function) not handled" | |
} | |
} | |
class ParentCoordinator: UIResponder { | |
override func accountLogin() -> String { | |
return "handled in ParentCoordinator" | |
} | |
} | |
class ChildCoordinator: UIResponder { | |
override func accountLogin() -> String { | |
return "handled in ChildCoordinator" | |
} | |
} | |
class ParentVC: UIViewController { | |
let coordinator = ParentCoordinator() | |
let child = ChildVC(nibName: nil, bundle: nil) | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .yellow | |
view.addSubview(child.view) | |
child.view.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate([ | |
child.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 100), | |
child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100), | |
child.view.widthAnchor.constraint(equalToConstant: 200), | |
child.view.heightAnchor.constraint(equalToConstant: 200)]) | |
addChild(child) | |
child.didMove(toParent: self) | |
} | |
override var coordinatingResponder: UIResponder? { | |
return coordinator | |
} | |
func didTapLogin() { | |
print("ParentVC:", accountLogin()) | |
} | |
} | |
class ChildVC: UIViewController { | |
let coordinator = ChildCoordinator() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .green | |
} | |
override var coordinatingResponder: UIResponder? { | |
return coordinator | |
} | |
func didTapLogin() { | |
print("ChildVC:", accountLogin()) | |
} | |
} | |
let parentVC = ParentVC(nibName: nil, bundle: nil) | |
import PlaygroundSupport | |
PlaygroundPage.current.liveView = parentVC | |
parentVC.didTapLogin() | |
parentVC.child.didTapLogin() | |
let uivc = UIViewController(nibName: nil, bundle: nil) | |
print("UIViewController:", uivc.accountLogin()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment