Skip to content

Instantly share code, notes, and snippets.

View twittemb's full-sized avatar

Thibault Wittemberg twittemb

View GitHub Profile
protocol ViewModelBased: class {
associatedtype ViewModelType: ViewModel
var viewModel: ViewModelType { get set }
}
extension ViewModelBased where Self: StoryboardBased & UIViewController {
static func instantiate<ServicesT> (withServices services: ServicesT) -> Self
where ServicesT == Self.ViewModelType.Services {
let viewController = Self.instantiate()
viewController.viewModel = ViewModelType(withServices: services)
return viewController
}
}
class MyService {
func executeService() {
print ("Service execution")
}
}
struct MyViewModel: ViewModel {
typealias Services = MyService
init(withServices services: Services) {
services.executeService()
}
}
let myViewController = MyViewController.instantiate(withServices: myService)
// we can access the inner ViewModel if needed: myViewController.viewModel
class Service1 {
func executeService1() {
print ("execution of Service1")
}
}
class Service2 {
func executeService2() {
print ("execution of Service2")
}
protocol HasService1 {
var service1: Service1 { get }
}
protocol HasService2 {
var service2: Service2 { get }
}
protocol HasService3 {
var service3: Service3 { get }
struct MyViewModel: ViewModel {
// thanks to protocol composition we define only the services we want to use
typealias Services = HasService1 & HasService2
init(withServices services: Services) {
services.service1.executeService1()
services.service2.executeService2()
}
}
struct MyOtherViewModel: ViewModel {
class MyServices: HasService1, HasService2, HasService3 {
let service1 = Service1()
let service2 = Service2()
let service3 = Service3()
}
let myViewController = MyViewController.instantiate(withServices: myServices)
let myViewController2 = MyViewController2.instantiate(withServices: myServices)
// This is the same myServices instance for the 2 ViewControllers
// but each ViewModel will only access what's needed