{"id":18060645,"url":"https://github.com/0xleif/appdependency","last_synced_at":"2025-09-22T18:31:46.472Z","repository":{"id":226518617,"uuid":"768382452","full_name":"0xLeif/AppDependency","owner":"0xLeif","description":"🧠 Effortless Dependency Injection for Swift Applications. Dependency only mirror of AppState","archived":false,"fork":false,"pushed_at":"2024-03-10T17:30:57.000Z","size":54,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-14T19:36:03.130Z","etag":null,"topics":["apple","depedency-injection","ios","linux","macos","observable","property-wrapper","published","swift","swiftui","tvos","ubuntu","visionos","watchos","windows"],"latest_commit_sha":null,"homepage":"https://0xleif.github.io/AppDependency/","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/0xLeif.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":["0xLeif"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2024-03-07T01:20:46.000Z","updated_at":"2024-11-13T11:10:54.000Z","dependencies_parsed_at":"2024-03-08T02:29:27.496Z","dependency_job_id":"8709381d-85ca-491c-b1c1-0661fdcf705c","html_url":"https://github.com/0xLeif/AppDependency","commit_stats":null,"previous_names":["0xleif/appdependency"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xLeif%2FAppDependency","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xLeif%2FAppDependency/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xLeif%2FAppDependency/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xLeif%2FAppDependency/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xLeif","download_url":"https://codeload.github.com/0xLeif/AppDependency/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233876672,"owners_count":18744248,"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":["apple","depedency-injection","ios","linux","macos","observable","property-wrapper","published","swift","swiftui","tvos","ubuntu","visionos","watchos","windows"],"created_at":"2024-10-31T04:10:02.884Z","updated_at":"2025-09-22T18:31:41.198Z","avatar_url":"https://github.com/0xLeif.png","language":"Swift","funding_links":["https://github.com/sponsors/0xLeif"],"categories":[],"sub_categories":[],"readme":"# AppDependency\n\nAppDependency is a Swift Package that simplifies the management of application dependencies in a thread-safe, type-safe, and SwiftUI-friendly way. Featuring dedicated struct types for managing dependencies, AppDependency provides easy and coordinated access to dependencies across your application. Added to this, the package incorporates built-in logging mechanisms to aid debugging and error tracking. The AppDependency package also boasts a cache-based system to persistently store and retrieve any application-wide data at any given time.\n\n*AppDependency is a dependency only mirror of [AppState](https://github.com/0xLeif/AppState).*\n\n**Requirements:** iOS 15.0+ / watchOS 8.0+ / macOS 11.0+ / tvOS 15.0+ / visionOS 1.0+ | Swift 5.9+ / Xcode 15+\n\n**Non Apple Platform Support:** Linux \u0026 Windows\n\n\n## Key Features\n\n(🍎 Apple OS only)\n\n### Dependency Management\n\n- **Dependency:** Struct for encapsulating dependencies within the app's scope.\n- **Scope:** Represents a specific context within an app, defined by a unique name and ID.\n\n### Fine-Grained Control\n\n- **DependencySlice:** Struct that provides access to and modification of specific AppDependency's dependency parts.\n\n### Property Wrappers\n\n- **AppDependency:** Simplifies the handling of dependencies throughout your application.\n- 🍎 **ObservedDependency:** Simplifies the handling of dependencies throughout your application. Dependencies must conform to ObservableObject. Backed by an `@ObservedObject` to publish changes to SwiftUI views.\n- **DependencySlice:** Allows users to access and modify a specific part of AppDependency's dependency.\n- **DependencyConstant:** Allows users to access a specific part of AppDependency's dependency.\n\n## Getting Started\n\nTo integrate AppDependency into your Swift project, you'll need to use the Swift Package Manager (SPM). SPM makes it easy to manage Swift package dependencies. Here's what you need to do:\n\n1. Add a package dependency to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/0xLeif/AppDependency.git\", from: \"1.0.0\")\n]\n```\n\nIf you're working with an App project, open your project in Xcode. Navigate to `File \u003e Swift Packages \u003e Add Package Dependency...` and enter `https://github.com/0xLeif/AppDependency.git`.\n\n2. Next, don't forget to add AppDependency as a target to your project. This step is necessary for both Xcode and SPM Package.swift.\n\nAfter successfully adding AppDependency as a dependency, you need to import AppDependency into your Swift file where you want to use it. Here's a code example:\n\n```swift\nimport AppDependency\n```\n\n## Usage\n\n### Defining Dependencies\n\n`Dependency` is a feature provided by AppDependency, allowing you to define shared resources or services in your application.\n\nTo define a dependency, you should extend the `Application` object. Here's an example of defining a `networkService` dependency:\n\n```swift\nextension Application {\n    var networkService: Dependency\u003cNetworkServiceType\u003e {\n        dependency(NetworkService())\n    }\n}\n```\n\nIn this example, `Dependency\u003cNetworkServiceType\u003e` represents a type safe container for `NetworkService`.\n\n### Reading and Using Dependencies\n\nOnce you've defined a dependency, you can access it anywhere in your app:\n\n```swift\nlet networkService = Application.dependency(\\.networkService)\n```\n\nThis approach allows you to work with dependencies in a type-safe manner, avoiding the need to manually handle errors related to incorrect types.\n\n### AppDependency Property Wrapper\n\nAppDependency provides the `@AppDependency` property wrapper that simplifies access to dependencies. When you annotate a property with `@AppDependency`, it fetches the appropriate dependency from the `Application` object directly.\n\n```swift\nstruct ContentView: View {\n    @AppDependency(\\.networkService) var networkService\n\n    // Your view code\n}\n```\n\nIn this case, ContentView has access to the networkService dependency and can use it within its code.\n\n### Using Dependency with ObservableObject\n\nWhen your dependency is an `ObservableObject`, any changes to it will automatically update your SwiftUI views. Make sure your service conforms to the `ObservableObject` protocol. To do this, you should not use the `@AppDependency` property wrapper, but instead use the `@ObservedDependency` property wrapper. \n\nHere's an example:\n\n```swift\nclass DataService: ObservableObject {\n    @Published var data: [String]\n\n    func fetchData() { ... }\n}\n\nextension Application {\n    var dataService: Dependency\u003cDataService\u003e {\n        dependency(DataService())\n    }\n}\n\nstruct ContentView: View {\n    @ObservedDependency(\\.dataService) private var dataService\n\n    var body: some View {\n        List(dataService.data, id: \\.self) { item in\n            Text(item)\n        }\n        .onAppear {\n            dataService.fetchData()\n        }\n    }\n}\n```\n\nIn this example, whenever data in `DataService` changes, SwiftUI automatically updates the `ContentView`.\n\n### Testing with Mock Dependencies\n\nOne of the great advantages of using `Dependency` in AppDependency is the capability to replace dependencies with mock versions during testing. This is incredibly useful for isolating parts of your application for unit testing. \n\nYou can replace a dependency by calling the `Application.override` function. This function returns a `DependencyOverride`, you'll want to hold onto this token for as long as you want the mock dependency to be effective. When the token is deallocated, the dependency reverts back to its original condition.\n\nHere's an example:\n\n```swift\n// Real network service\nextension Application {\n    var networkService: Dependency\u003cNetworkServiceType\u003e {\n        dependency(NetworkService())\n    }\n}\n\n// Mock network service\nclass MockNetworkService: NetworkServiceType {\n    // Your mock implementation\n}\n\nfunc testNetworkService() {\n    // Keep hold of the `DependencyOverride` for the duration of your test.\n    let networkOverride = Application.override(\\.networkService, with: MockNetworkService())\n\n    let mockNetworkService = Application.dependency(\\.networkService)\n    \n    // Once done, you can allow the `DependencyOverrideen` to be deallocated \n    // or call `networkOverride.cancel()` to revert back to the original service.\n}\n```\n\n### SwiftUI Previews\n\nTo override a dependency inside a SwiftUI preview, you must use the Environment.preview function and pass in the dependency overrides with the content.\n\n```swift\nclass Service {\n    var title: String { \"Live Service\" }\n}\n\nclass MockService: Service {\n    override var title: String { \"Mock Service\" }\n}\n\nextension Application {\n    var service: Dependency\u003cService\u003e {\n        dependency(Service())\n    }\n}\n\nstruct ContentView: View {\n    @AppDependency(\\.service) private var service\n\n    var body: some View {\n        Text(service.title)\n    }\n}\n\n#Preview {\n    Application.preview(\n        Application.override(\\.service, with: MockService()),\n        Application.override(\\.userDefaults, with: UserDefaults())\n    ) {\n        ContentView()\n    }\n}\n```\n\n## License\n\nAppDependency is released under the MIT License. See [LICENSE](https://github.com/0xLeif/AppDependency/blob/main/LICENSE) for more information.\n\n## Communication and Contribution\n\n- If you found a bug, open an issue.\n- If you have a feature request, open an issue.\n- If you want to contribute, submit a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xleif%2Fappdependency","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xleif%2Fappdependency","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xleif%2Fappdependency/lists"}