Skip to content

Instantly share code, notes, and snippets.

@werediver
Last active July 8, 2020 10:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save werediver/8cda3d833eec044d36876883a451bad1 to your computer and use it in GitHub Desktop.
Save werediver/8cda3d833eec044d36876883a451bad1 to your computer and use it in GitHub Desktop.
View Transition mechanism for MVVM pattern (Swift, iOS)
import UIKit
// MARK: - Specification
protocol ViewType {
associatedtype ViewModel: ViewModelType
var viewModel: ViewModel { get }
//init(viewModel: ViewModel) // Not possible for storyboard-based view controllers.
static func instantiate(viewModel viewModel: ViewModel) -> Self
}
protocol ViewModelType {
associatedtype Model
var model: Model { get }
init(model: Model)
}
protocol ViewFactoryType {
associatedtype View: ViewType
func createView(model model: View.ViewModel.Model) -> View
}
protocol ModelTransformationType {
associatedtype SrcModel
associatedtype DstModel
func transform(m: SrcModel) -> DstModel
}
protocol ViewPresentationType {
associatedtype SrcView: ViewType
associatedtype DstView: ViewType
func present(srcView srcView: SrcView, dstView: DstView)
}
protocol ViewTransitionType {
associatedtype SrcView: ViewType
func performTransition(srcView srcView: SrcView)
}
// MARK: - Implementation
final class ModelTransformation<SrcModel, DstModel>: ModelTransformationType {
private let body: SrcModel -> DstModel
init(body: SrcModel -> DstModel) {
self.body = body
}
func transform(m: SrcModel) -> DstModel {
return body(m)
}
}
final class PushPresentation<SrcView: ViewType, DstView: ViewType
where SrcView: UIViewController, DstView: UIViewController>: ViewPresentationType
{
private let animated: Bool
init(animated: Bool) {
self.animated = animated
}
func present(srcView srcView: SrcView, dstView: DstView) {
srcView.navigationController?.pushViewController(dstView, animated: animated)
}
}
final class ViewTransition<ModelTransformation: ModelTransformationType, DstViewFactory: ViewFactoryType, ViewPresentation: ViewPresentationType
where ModelTransformation.SrcModel == ViewPresentation.SrcView.ViewModel.Model,
ModelTransformation.DstModel == ViewPresentation.DstView.ViewModel.Model,
DstViewFactory.View == ViewPresentation.DstView>: ViewTransitionType
{
private let viewPresentation: ViewPresentation
private let dstViewFactory: DstViewFactory
private let modelTransformation: ModelTransformation
init(viewPresentation: ViewPresentation, dstViewFactory: DstViewFactory, modelTransformation: ModelTransformation) {
self.viewPresentation = viewPresentation
self.dstViewFactory = dstViewFactory
self.modelTransformation = modelTransformation
}
func performTransition(srcView srcView: ViewPresentation.SrcView) {
let dstView = srcView.viewModel.model |> modelTransformation.transform |> dstViewFactory.createView
viewPresentation.present(srcView: srcView, dstView: dstView)
}
}
/// A type-erased view transition.
final class AnyViewTransition<SrcView: ViewType>: ViewTransitionType {
private let _performTransition: SrcView -> ()
init<T: ViewTransitionType where T.SrcView == SrcView>(transition: T) {
self._performTransition = { transition.performTransition(srcView: $0) }
}
func performTransition(srcView srcView: SrcView) {
_performTransition(srcView)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment