Last active
January 10, 2019 11:56
-
-
Save cojoj/56d73a1b57a86b7c45277a3e4152ed0b to your computer and use it in GitHub Desktop.
This is a test MVVHP architecture. It's just a proof of concept.
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
import UIKit | |
// We need a definition of a Presenter. | |
// It'll have associated type for handler, propety of this type and a possibility to | |
// bind a View Handler. | |
protocol Presenter { | |
associatedtype ViewHandler: BaseViewHandler | |
var viewHandler: ViewHandler? { get set } | |
mutating func bind(handler: ViewHandler) | |
} | |
// Our basic requirements for View Handlers are defined in this protocol. | |
// What is ViewHandler? It's a way proxy for communicating Presenter changes to the View. | |
protocol BaseViewHandler { | |
func setTitle(_ title: String) | |
func showStatus(_ status: String, animated: Bool) | |
func hideStatus(animated: Bool) | |
} | |
// We're creating a Base View Controller which we'll always subclass, so we can put there some stuff | |
// like property for a Presenter etc. | |
class BaseViewController<P: Presenter>: UIViewController { | |
var presenter: P | |
init(presenter: P) { | |
self.presenter = presenter | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("Not Implemented") | |
} | |
override func loadView() { | |
self.view = UIView() | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
} | |
} | |
// We make our Base View Controller conform to Base View Handler, so it can react to some top-level | |
// actions common to all views. | |
extension BaseViewController: BaseViewHandler { | |
func setTitle(_ title: String) { | |
} | |
func showStatus(_ status: String, animated: Bool) { | |
} | |
func hideStatus(animated: Bool) { | |
} | |
} | |
// Our classes | |
// This is a specific View Handler decalration with a methods related to specific View/VC | |
protocol TestViewHandler: BaseViewHandler { | |
func testMethod() | |
} | |
// Impelmentation of a specialized VC. | |
// As you can see, it has access to it's dedicated Presenter | |
final class TestViewController: BaseViewController<TestPresenter> { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
presenter.calucateSomething() | |
print(presenter.something) | |
} | |
} | |
// We're making this VC being a ViewHandler. We could pass here everything, but the problem is that | |
// we don't want to reimplement BaseViewHandler's methods. | |
extension TestViewController: TestViewHandler { | |
func testMethod() { | |
} | |
} | |
// I know... | |
// Tight coupling | |
// Tight coupling | |
// Tight coupling | |
// Tight coupling | |
// ... But only as a typealias 🤗 | |
// Thanks to this we have only one ViewHandler. Of course, we can have two of them and pass here | |
struct TestPresenter: Presenter { | |
typealias ViewHandler = TestViewController | |
var viewHandler: ViewHandler? | |
mutating func bind(handler: ViewHandler) { | |
self.viewHandler = handler | |
} | |
let something = "Something" | |
func calucateSomething() -> Int { | |
return 2 | |
} | |
} | |
// Usage | |
var preseter = TestPresenter() | |
let vc = TestViewController(presenter: preseter) | |
preseter.bind(handler: vc) | |
// There's also a question, where's View Model in all this. | |
// View Model is just a way of transforming data into digestable format for other views. | |
// In the end it's just getting a data from Presenter, modifying it a bit and passing somewhere else. | |
// Do we need an object (struct) for this? I don't think so. I think we can just create | |
// a protocol with definitions and make Presenter conform to it. | |
// We'd skip another initializations and data juggling. | |
protocol DetailedTestViewModel { | |
var uppercasedSomething: String { get } | |
} | |
extension TestPresenter: DetailedTestViewModel { | |
var uppercasedSomething: String { | |
return something.uppercased() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment