{"id":27105220,"url":"https://github.com/techpro-studio/swiftuiapparchitecture","last_synced_at":"2026-05-17T17:43:28.057Z","repository":{"id":38745742,"uuid":"221928734","full_name":"techpro-studio/SwiftUIAppArchitecture","owner":"techpro-studio","description":"SwiftUI App architecture we use.  Feel free to contribute!","archived":false,"fork":false,"pushed_at":"2020-02-16T12:34:18.000Z","size":17,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-06T18:49:19.872Z","etag":null,"topics":["architecture","factories","mvvm","swiftui","swinject"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/techpro-studio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-15T13:23:37.000Z","updated_at":"2022-06-23T15:51:26.000Z","dependencies_parsed_at":"2022-09-12T03:00:35.983Z","dependency_job_id":null,"html_url":"https://github.com/techpro-studio/SwiftUIAppArchitecture","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/techpro-studio/SwiftUIAppArchitecture","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techpro-studio%2FSwiftUIAppArchitecture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techpro-studio%2FSwiftUIAppArchitecture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techpro-studio%2FSwiftUIAppArchitecture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techpro-studio%2FSwiftUIAppArchitecture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/techpro-studio","download_url":"https://codeload.github.com/techpro-studio/SwiftUIAppArchitecture/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techpro-studio%2FSwiftUIAppArchitecture/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266689005,"owners_count":23969139,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["architecture","factories","mvvm","swiftui","swinject"],"created_at":"2025-04-06T18:37:37.724Z","updated_at":"2026-05-17T17:43:23.025Z","avatar_url":"https://github.com/techpro-studio.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftUIAppArchitecture\n\nSwiftUI app architecture we use.\n\nMVVM-F = MVVM architecture + Factory;\n\nSOLID principles are the core of our architecture.\n\n\n## 1. For assembling project we use DI pattern with [Swinject](https://github.com/Swinject/Swinject) library.\n\nApp 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.\n\n## 2. Every View Module for [example](https://github.com/techpro-studio/SwiftUIAppArchitecture/tree/master/SwiftUIAppArchitecture/Main) has the following structure:\n\n### Factory \n  Abstraction for creation View. Factory is very important part of this architecture, because it injects dependencies. \n [BaseFactory](https://github.com/techpro-studio/RCKit/blob/master/Sources/RCKit/BaseFactory.swift) contains Container we use to inject dependencies that we need.\n 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.\n  \n```swift\n  protocol \u003cName\u003eViewFactory {\n    func make()-\u003e AnyView\n  } \n```\n\n### ViewModel\n  It contains the logic of the presentation. It has the bindings for input and output.\n  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, \n  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.\n \n ```swift\n \n // for example\n class \u003cName\u003eViewModel : ObservableObject {\n \n     private let reachabillityManager:  ReachabilityManager\n \n     init(reachabillityManager: ReachabilityManager) {\n         self.reachabillityManager = reachabillityManager\n         super.init()\n         self.computePublishers()\n     }\n \n     @Published  var input: String = \"\"\n     @Published  var isButtonEnabled = false\n \n \n     func computePublishers() {\n \n         self.reachabillityManager.reachable.combineLatest($input).map { (reachable, input) -\u003e Bool in\n             if !reachable{\n                 return false\n             }\n             return input.count \u003e= 5\n         }.receive(on: RunLoop.main)\n         .assign(to: \\MainViewModel.isButtonEnabled, on: self)\n         .store(in: \u0026cancellableBag)\n \n     }\n \n \n }\n  ```\n  \n### View \nJust simple SwiftUI view.   \nIt contains viewModel and child view factories.\n  \n  ```swift\n    struct \u003cName\u003eView: View {\n    \n        @ObservedObject var viewModel: \u003cName\u003eViewModel\n        let otherViewFactory: \u003cOther\u003eViewFactory\n    \n        @State private var isActiveDetail = false\n    \n        var body: some View {\n            NavigationView {\n                VStack {\n                    TextField(\"Input\", text: $viewModel.input).frame(height: 50.0)\n                    NavigationLink(destination: otherViewFactory.make(value: viewModel.input), isActive: $isActiveDetail, label: {Text(\"GO!\")}).disabled(!viewModel.isButtonEnabled)\n                }.frame(width: 200.0).navigationBarTitle(\"Main\")\n            }\n        }\n    }\n  ```\n  \n\n  \n  \n  \n  \n  \n  \n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechpro-studio%2Fswiftuiapparchitecture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftechpro-studio%2Fswiftuiapparchitecture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechpro-studio%2Fswiftuiapparchitecture/lists"}