https://github.com/techpro-studio/swiftuiapparchitecture
SwiftUI App architecture we use. Feel free to contribute!
https://github.com/techpro-studio/swiftuiapparchitecture
architecture factories mvvm swiftui swinject
Last synced: about 1 month ago
JSON representation
SwiftUI App architecture we use. Feel free to contribute!
- Host: GitHub
- URL: https://github.com/techpro-studio/swiftuiapparchitecture
- Owner: techpro-studio
- Created: 2019-11-15T13:23:37.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2020-02-16T12:34:18.000Z (about 5 years ago)
- Last Synced: 2024-04-21T17:02:31.437Z (about 1 year ago)
- Topics: architecture, factories, mvvm, swiftui, swinject
- Language: Swift
- Size: 16.6 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# SwiftUIAppArchitecture
SwiftUI app architecture we use.
MVVM-F = MVVM architecture + Factory;
SOLID principles are the core of our architecture.
## 1. For assembling project we use DI pattern with [Swinject](https://github.com/Swinject/Swinject) library.
App has shared [Container](https://github.com/Swinject/Swinject/blob/master/Documentation/DIContainer.md) where we register all shared dependencies we need to use across the whole app.
## 2. Every View Module for [example](https://github.com/techpro-studio/SwiftUIAppArchitecture/tree/master/SwiftUIAppArchitecture/Main) has the following structure:
### Factory
Abstraction for creation View. Factory is very important part of this architecture, because it injects dependencies.
[BaseFactory](https://github.com/techpro-studio/RCKit/blob/master/Sources/RCKit/BaseFactory.swift) contains Container we use to inject dependencies that we need.
We can inject factories in other views via DI and it gives us a lot of flexibility. We use type erased AnyView for more flexibility.
```swift
protocol ViewFactory {
func make()-> AnyView
}
```### ViewModel
It contains the logic of the presentation. It has the bindings for input and output.
The biggest problem here is that ObservableObject has Self requirement and can't be used as an Abstraction like a protocol and even as an abstract class. If you try to use ConcreteViewModel as a child of a base abstract ViewModel class with properties and abstract methods,
then @Published properties will not update the view. And this is a huge fail for flexibility because we can't use viewModel as an abstraction.
```swift
// for example
class ViewModel : ObservableObject {
private let reachabillityManager: ReachabilityManager
init(reachabillityManager: ReachabilityManager) {
self.reachabillityManager = reachabillityManager
super.init()
self.computePublishers()
}
@Published var input: String = ""
@Published var isButtonEnabled = false
func computePublishers() {
self.reachabillityManager.reachable.combineLatest($input).map { (reachable, input) -> Bool in
if !reachable{
return false
}
return input.count >= 5
}.receive(on: RunLoop.main)
.assign(to: \MainViewModel.isButtonEnabled, on: self)
.store(in: &cancellableBag)
}
}
```
### View
Just simple SwiftUI view.
It contains viewModel and child view factories.
```swift
struct View: View {
@ObservedObject var viewModel: ViewModel
let otherViewFactory: ViewFactory
@State private var isActiveDetail = false
var body: some View {
NavigationView {
VStack {
TextField("Input", text: $viewModel.input).frame(height: 50.0)
NavigationLink(destination: otherViewFactory.make(value: viewModel.input), isActive: $isActiveDetail, label: {Text("GO!")}).disabled(!viewModel.isButtonEnabled)
}.frame(width: 200.0).navigationBarTitle("Main")
}
}
}
```