{"id":789,"url":"https://github.com/nalexn/clean-architecture-swiftui","last_synced_at":"2025-05-13T16:11:35.968Z","repository":{"id":37432039,"uuid":"218088093","full_name":"nalexn/clean-architecture-swiftui","owner":"nalexn","description":"SwiftUI sample app using Clean Architecture. Examples of working with SwiftData persistence, networking, dependency injection, unit testing, and more.","archived":false,"fork":false,"pushed_at":"2024-12-09T05:43:12.000Z","size":455,"stargazers_count":6116,"open_issues_count":23,"forks_count":743,"subscribers_count":107,"default_branch":"master","last_synced_at":"2025-04-09T02:03:53.709Z","etag":null,"topics":["architecture","clean-architecture","cleanarchitecture","demo","example-project","interactor","mvvm","sample","swift","swift-data","swift-testing","swiftdata","swiftui","swiftui-example","viewinspector"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nalexn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["nalexn"],"custom":["https://venmo.com/nallexn"]}},"created_at":"2019-10-28T16:00:51.000Z","updated_at":"2025-04-08T08:08:49.000Z","dependencies_parsed_at":"2024-06-21T00:20:27.745Z","dependency_job_id":"c317af9e-4f86-4f96-8593-158ab04eecdc","html_url":"https://github.com/nalexn/clean-architecture-swiftui","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fclean-architecture-swiftui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fclean-architecture-swiftui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fclean-architecture-swiftui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2Fclean-architecture-swiftui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nalexn","download_url":"https://codeload.github.com/nalexn/clean-architecture-swiftui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514767,"owners_count":21443208,"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","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","clean-architecture","cleanarchitecture","demo","example-project","interactor","mvvm","sample","swift","swift-data","swift-testing","swiftdata","swiftui","swiftui-example","viewinspector"],"created_at":"2024-01-05T20:15:31.354Z","updated_at":"2025-04-23T21:02:07.681Z","avatar_url":"https://github.com/nalexn.png","language":"Swift","funding_links":["https://github.com/sponsors/nalexn","https://venmo.com/nallexn"],"categories":["Architecture Patterns","🛠 Examples","Samples","Swift","개발문화","Misc","Swift UI","🌎 by the community"],"sub_categories":["Open Source Apps","Getting Started","iOS 아키텍처 레포지터리","SwiftUI","macOS"],"readme":"### Articles related to this project\n\n* [Clean Architecture for SwiftUI](https://nalexn.github.io/clean-architecture-swiftui/?utm_source=nalexn_github)\n* [Programmatic navigation in SwiftUI project](https://nalexn.github.io/swiftui-deep-linking/?utm_source=nalexn_github)\n* [Separation of Concerns in Software Design](https://nalexn.github.io/separation-of-concerns/?utm_source=nalexn_github)\n\n---\n\n# Clean Architecture for SwiftUI + Combine\n\nA demo project showcasing the setup of the SwiftUI app with Clean Architecture.\n\nThe app uses the [restcountries.com](https://restcountries.com/) REST API to show the list of countries and details about them.\n\n**Check out [mvvm branch](https://github.com/nalexn/clean-architecture-swiftui/tree/mvvm) for the MVVM revision of the same app.**\n\nFor the example of handling the **authentication state** in the app, you can refer to my [other tiny project](https://github.com/nalexn/uikit-swiftui) that harnesses the locks and keys principle for solving this problem.\n\n![platforms](https://img.shields.io/badge/platforms-iPhone%20%7C%20iPad%20%7C%20macOS-lightgrey) [![codecov](https://codecov.io/gh/nalexn/clean-architecture-swiftui/branch/master/graph/badge.svg)](https://codecov.io/gh/nalexn/clean-architecture-swiftui) [![codebeat badge](https://codebeat.co/badges/db33561b-0b2b-4ee1-a941-a08efbd0ebd7)](https://codebeat.co/projects/github-com-nalexn-clean-architecture-swiftui-master)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/nalexn/blob_files/blob/master/images/countries_preview.png?raw=true\" alt=\"Diagram\"/\u003e\n\u003c/p\u003e\n\n## Key features\n* End of 2024 update: the project was fully revamped to use modern iOS stack technologies\n* Decoupled **Presentation**, **Business Logic**, and **Data Access** layers\n* Programmatic navigation. Push notifications with deep link\n* Redux-like centralized `AppState` as the single source of truth\n* Native SwiftUI dependency injection\n* Handling of the system events (such as `didBecomeActive`, `willResignActive`)\n* Full test coverage, including the UI (thanks to the [ViewInspector](https://github.com/nalexn/ViewInspector))\n* Simple yet flexible networking layer built on async - await\n* UI - vanilla **SwiftUI** + **Combine**\n* Data persistence with **SwiftData**\n\n## Architecture overview\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/nalexn/blob_files/blob/master/images/swiftui_arc_001.png?raw=true\" alt=\"Diagram\"/\u003e\n\u003c/p\u003e\n\n### Presentation Layer\n\n**SwiftUI views** that contain no business logic and are a function of the state.\n\nSide effects are triggered by the user's actions (such as a tap on a button) or view lifecycle event `onAppear` and are forwarded to the `Interactors`.\n\nState and business logic layer (`AppState` + `Interactors`) are natively injected into the view hierarchy with `@Environment`.\n\n### Business Logic Layer\n\nBusiness Logic Layer is represented by `Interactors`. \n\nInteractors receive requests to perform work, such as obtaining data from an external source or making computations, but they never return data back directly.\n\nInstead, they forward the result to the `AppState` or to a `Binding`. The latter is used when the result of work (the data) is used locally by one View and does not belong to the `AppState`.\n\n[Previously](https://github.com/nalexn/clean-architecture-swiftui/releases/tag/1.0), this app did not use CoreData for persistence, and all loaded data were stored in the `AppState`.\n\nWith the persistence layer in place we have a choice - either to load the DB content onto the `AppState`, or serve the data from `Interactors` on an on-demand basis through `Binding`.\n\nThe first option suits best when you don't have a lot of data, for example, when you just store the last used login email in the `UserDefaults`. Then, the corresponding string value can just be loaded onto the `AppState` at launch and updated by the `Interactor` when the user changes the input.\n\nThe second option is better when you have massive amounts of data and introduce a fully-fledged database for storing it locally.\n\n### Data Access Layer\n\nData Access Layer is represented by `Repositories`.\n\nRepositories provide asynchronous API (`Publisher` from Combine) for making [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations on the backend or a local database. They don't contain business logic, neither do they mutate the `AppState`. Repositories are accessible and used only by the Interactors.\n\n---\n\n[![Twitter](https://img.shields.io/badge/twitter-nallexn-blue)](https://twitter.com/nallexn) [![blog](https://img.shields.io/badge/blog-github-blue)](https://nalexn.github.io/?utm_source=nalexn_github)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fclean-architecture-swiftui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnalexn%2Fclean-architecture-swiftui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fclean-architecture-swiftui/lists"}