Skip to content

Instantly share code, notes, and snippets.

@thelowlypeon
Created September 26, 2018 19:07
Show Gist options
  • Save thelowlypeon/94d2fd7a61148e857902eee2adc805a3 to your computer and use it in GitHub Desktop.
Save thelowlypeon/94d2fd7a61148e857902eee2adc805a3 to your computer and use it in GitHub Desktop.
import Foundation
import UIKit
public class Event<T> {
public typealias EventHandler = (T) -> Void
private var eventHandlers = [EventHandler]()
public func addHandler(handler: @escaping EventHandler, withInitialEvent initialEvent: T? = nil) {
eventHandlers.append(handler)
if let event = initialEvent {
handler(event)
}
}
public func raise(_ data: T) {
for handler in eventHandlers {
handler(data)
}
}
}
public enum PersonProperty {
case initial, firstName, middleInitial, lastName
}
public class Person {
public let propertyChanged = Event<PersonProperty>()
public var firstName: String { didSet { propertyChanged.raise(.firstName) } }
public var middleInitial: String? { didSet { propertyChanged.raise(.middleInitial) } }
public var lastName: String { didSet { propertyChanged.raise(.lastName) } }
public init(firstName: String, middleInitial: String?, lastName: String) {
self.firstName = firstName
self.middleInitial = middleInitial
self.lastName = lastName
}
public func abbreviateName() {
firstName.removeLast()
}
}
let me = Person(firstName: "Peter", middleInitial: nil, lastName: "Compernolle")
let daisy = Person(firstName: "Daisy", middleInitial: nil, lastName: "Jiang")
public enum PersonViewModelProperty {
case initial, person, personNameText, abbreviateNameButtonEnabled
}
public class PersonViewModel {
// observable properties
public let propertyChanged = Event<PersonViewModelProperty>()
public var personNameText: String?
public var abbreviateNameButtonEnabled: Bool { return person != nil }
public init(person: Person?) {
self.person = person
bindPerson()
}
// MARK: observe changes to data models
public var person: Person? { didSet { propertyChanged.raise(.person) } }
private func bindPerson() {
self.propertyChanged.addHandler(handler: {[unowned self](property) in
switch property {
case .initial, .person:
self.person?.propertyChanged.addHandler(handler: {[unowned self](property) in
self.propertyChanged.raise(.abbreviateNameButtonEnabled)
guard let person = self.person else { return }
self.personNameText = "\(person.firstName) \(person.lastName)"
self.propertyChanged.raise(.personNameText)
}, withInitialEvent: .initial)
default: return
}
}, withInitialEvent: .initial)
}
@objc public func didPressAbbreviateName() {
self.person?.abbreviateName()
}
}
class PersonView {
var personNameLabel: UILabel
var abbreviateNameButton: UIButton
var backButton: UIButton
private var viewModel: PersonViewModel
init(person: Person?) {
viewModel = PersonViewModel(person: person)
personNameLabel = UILabel(frame: CGRect.zero)
abbreviateNameButton = UIButton(frame: CGRect.zero)
backButton = UIButton(frame: CGRect.zero)
backButton.addTarget(self, action: #selector(PersonView.viewWillDisappear), for: .touchUpInside)
viewWillAppear(animated: true)
}
func changePerson(person: Person?) {
viewModel.person = person
}
// mock
func viewWillAppear(animated: Bool) {
bindViewModel()
}
// mock
@objc func viewWillDisappear() {
unbindViewModel()
}
func bindViewModel() {
abbreviateNameButton.addTarget(viewModel, action: #selector(PersonViewModel.didPressAbbreviateName), for: .touchUpInside)
viewModel.propertyChanged.addHandler(handler: {(property) in
switch property {
case .personNameText, .initial:
self.personNameLabel.text = self.viewModel.personNameText
case .abbreviateNameButtonEnabled:
self.abbreviateNameButton.isEnabled = self.viewModel.abbreviateNameButtonEnabled
default: break
}
}, withInitialEvent: .initial)
}
func unbindViewModel() {
abbreviateNameButton.removeTarget(viewModel, action: #selector(PersonViewModel.didPressAbbreviateName), for: .touchUpInside)
}
}
func main() {
let me = Person(firstName: "Peter", middleInitial: nil, lastName: "C")
let daisy = Person(firstName: "Daisy", middleInitial: nil, lastName: "J")
let view = PersonView(person: nil)
print("button enabled? \(view.abbreviateNameButton.isEnabled)")
print(view.personNameLabel.text ?? "nil")
view.changePerson(person: me)
print("button enabled? \(view.abbreviateNameButton.isEnabled)")
print(view.personNameLabel.text ?? "nil")
view.abbreviateNameButton.sendActions(for: .touchUpInside)
print(view.personNameLabel.text ?? "nil")
view.changePerson(person: daisy)
print(view.personNameLabel.text ?? "nil")
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment