Skip to content

DependencyKit is a lightweight Swift package that provides a simple and type-safe way to manage dependencies in your applications.

License

Notifications You must be signed in to change notification settings

Stof83/DependencyKit

Repository files navigation

DependencyKit

Swift Version SPM Compatible License

This is a lightweight, flexible, and production-ready Dependency Injection (DI) system for Swift and SwiftUI apps, inspired by modern patterns from Clean Architecture and Domain-Driven Design. It supports both type-based and key-path-based registrations and resolutions, making it ideal for modular, scalable, and testable applications.

Features

  • ✅ Type-safe dependency resolution
  • ✅ KeyPath-based scoped dependency access
  • ✅ Property wrappers for SwiftUI and non-SwiftUI types
  • ✅ Clean API for registration and usage
  • ✅ Seamless integration with @StateObject and @ObservedObject
  • ✅ Support for both struct-based and class-based models

Installation

Use Swift Package Manager:

// swift-tools-version:6.1

import PackageDescription

let package = Package(
    name: "YourPackageName",
    dependencies: [
        .package(url: "https://github.com/Stof83/DependencyKit.git", from: "1.0.0")
    ],
    targets: [
        .target(
                name: "YourTargetName",
                dependencies: [
                    .product(name: "DependencyKit", package: "DependencyKit")
                ]
        )
    ]
)

Usage

Step 1: Define your Dependencies

class ViewModel1: ObservableObject {}
class ViewModel2: NSObject {}

Step 2: Register Dependencies

You can register dependencies by type or by key path.

Register by KeyPath

Extend DependencyValues to define scoped keys:

extension DependencyValues {
    var baseURL: URL {
        get { resolve(\.baseURL) }
        set { register(newValue, for: \.baseURL) }
    }
}

Register the dependency:

let baseURL = URL(string: "https://api.example.com")!
let dependencyManager = DependencyManager()
dependencyManager.register(baseURL, for: \.baseURL)

Register by Type

let viewModel1 = ViewModel1()
let viewModel2 = ViewModel2()

let dependencyManager = DependencyManager()
dependencyManager.register(dependencies: [
    (viewModel1, ViewModel1.self),
    (viewModel2, ViewModel2.self)
])

Injecting Dependencies

In SwiftUI Views

struct MyView: View {
    @InjectedStateObject var viewModel1: ViewModel1
    @Dependency(\.baseURL) var baseURL: URL

    var body: some View {
        VStack {
            Text("Base URL: \(baseURL.absoluteString)")
            Text("ViewModel1 class: \(String(describing: type(of: viewModel1)))")
        }
    }
}

In Non-SwiftUI Classes

class Service {
    @InjectedViewModel var viewModel2: ViewModel2

    func printType() {
        print("Injected ViewModel2 type: \(type(of: viewModel2))")
    }
}

Updating or Removing Dependencies

// Replace baseURL at runtime
dependencyManager.register(URL(string: "https://new.api.com")!, for: \.baseURL)

// Remove a dependency by type
dependencyManager.remove(ViewModel1.self)

Testing Tips

  • Register mock implementations for unit tests.
  • Use a custom DependencyContainer instance for isolation.
let testContainer = DependencyContainer()
testContainer.register(MockService() as ServiceProtocol, for: ServiceProtocol.self)

License

DependencyKit is released under the MIT license. See LICENSE for details.

About

DependencyKit is a lightweight Swift package that provides a simple and type-safe way to manage dependencies in your applications.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages