https://github.com/dgrzeszczak/mvvm
MVVM framework is swift library inspired by ViewModel from Android Architecture components.
https://github.com/dgrzeszczak/mvvm
ios-architecture ios-swift model-view-viewmodel mvvm mvvm-architecture
Last synced: 8 months ago
JSON representation
MVVM framework is swift library inspired by ViewModel from Android Architecture components.
- Host: GitHub
- URL: https://github.com/dgrzeszczak/mvvm
- Owner: dgrzeszczak
- License: mit
- Created: 2018-05-19T12:09:54.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2019-12-25T14:09:42.000Z (over 6 years ago)
- Last Synced: 2025-10-20T12:58:52.559Z (8 months ago)
- Topics: ios-architecture, ios-swift, model-view-viewmodel, mvvm, mvvm-architecture
- Language: Swift
- Homepage:
- Size: 26.4 KB
- Stars: 13
- Watchers: 1
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
*MVVM* framework is swift library inspired by *ViewModel* from Android Architecture components. I strongly recommend to look at [Android docs](https://developer.android.com/topic/libraries/architecture/viewmodel).
Working on *Model-View-ViewModel* architecture you can ask the question where you should instantiate *View Model* and how to pass it to the *View* (ie. ```UIViewController```). With *MVVM* framework you will use factories to create View Models. You can prepare your custom parametrized factory or use the default one ```InitializableViewModelFactory``` which works on ```Initializable``` ViewModels.
```swift
class MyViewModel: Initializable {
required init() { }
}
```
In your ViewController you can instantiate it by calling
```swift
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let vm: MyViewModel? = ViewModelProviders.provider(for: self).get()
}
}
```
## Lifecycle
*ViewModel* is created for specific contexts (*ViewControllers*) and live as long as the context (when context is deallocated, *ViewModel* will be deallocated automatically).
*View Model* is created by the factory when you call ```provider.get()``` method first time. You have to keep in mind all *View Models* are "cached" for specific context. It means that when you get the same type of View Model for the same context again it will return cached View Model, not a new one (eg. it can be useful for sharing data between views).
From time to time you may need to re-create *Viewm Model(s)* for the context. You can clear the context calling ```.clear()``` method from ```ViewModelStore``` but you have to know that all *View Models* will be removed for that context.
## Custom factories
When you need custom factory (eg. parameterized init for *ViewModel*) you can prepare it by implementing ```ViewModelFactory``` protocol.
```swift
struct MyViewModel { }
struct MySecondViewModel { }
struct ParamViewModel {
let intParam: Int
}
struct MyViewModelFactory: ViewModelFactory {
func create() -> VM? {
switch VM.self {
case is MyViewModel.Type: return MyViewModel() as? VM
case is MySecondViewModel.Type: return MySecondViewModel() as? VM
case is ParamViewModel.Type: return ParamViewModel(intParam: 3) as? VM
default: return nil
}
}
}
```
and then you can use it like that:
```swift
var provider = ViewModelProviders.provider(for: controller, with: MyViewModelFactory())
guard let viewModel: MyViewModel = provider.get() else { return }
```
Another way to make custom factory is to use helpers classes that use closures to create *View Model* ```SingleViewModelFactory``` or ```CompositeViewModelFactory``` eg:
```swift
let singleFactory = SingleViewModelFactory { ParamViewModel(intParam: 3) }
var compositeFactory = CompositeViewModelFactory()
compositeFactory.add { MyViewModel() }
compositeFactory.add { MySecondViewModel() }
compositeFactory.add { ParamViewModel(intParam: 3) }
```
## More "complicated" factory example with RX ;)
```swift
final class FindViewModelFactory: ViewModelFactory {
private let disposeBag = DisposeBag()
private var factory = CompositeViewModelFactory()
private lazy var findViewModel: FindViewModel = {
return FindViewModel()
}()
init() {
factory.add { [unowned self] in self.findViewModel }
factory.add { [unowned self] in self.createSearchGlobalViewModel() }
factory.add { BrandListViewModel(fetcher: ProductsWireframe.brandsFetcher) }
factory.add { ProductCategoryListViewModel() }
factory.add { ServiceCategoryListViewModel() }
}
private func createSearchGlobalViewModel() -> SearchGlobalViewModel {
let searchGlobalViewModel = SearchGlobalViewModel()
findViewModel.searchPredicate.asObservable().bind(to: searchGlobalViewModel.searchPredicate).disposed(by: disposeBag)
return searchGlobalViewModel
}
func create() -> VM? {
return factory.create()
}
}
```