Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

5 Commits

Repository files navigation

ForgeInject

Dependency injection for iOS with constructor and property wrapper support.

Swift 6.3+iOS 18+macOS 15+LicenseRelease


ForgeInject is a macro-based dependency injection library for iOS. It gives you three ways to resolve dependencies — one is probably the right fit for every scenario you'll encounter.

MacroUse whenResolution
@InjectableView models and services with stable dependencies. Constructor injection, swappable in tests.At init time
@InjectHeavy or optional properties that may never be touched. Lazy + cached + thread-safe.On first access
#inject()Local variables, default parameters, let in structs.Where used

Features

  • Three macros for three injection patterns — pick whichever suits each dependency
  • Testable by design@Injectable generates an init that accepts overrides, so tests don't need to touch the container
  • Thread-safe@Inject's lazy form is backed by Mutex<T?> from the Synchronization framework
  • Three retain policies.transient, .singleton, .weak
  • Modular registration via ForgeRegisterProtocol for feature-based organization
  • Explicit error handling via ForgeContainerError

Requirements

  • iOS 18+
  • macOS 15+
  • Swift 6.3+ (Xcode 26 or later)

Installation

Xcode

  1. File → Add Package Dependencies…
  2. Paste https://github.com/stefanprojchev/ForgeInject.git
  3. Set rule to Up to Next Major from 1.0.0

Package.swift

dependencies:[.package(url:"https://github.com/stefanprojchev/ForgeInject.git", from:"1.0.0")],targets:[.target(
name:"YourApp",
dependencies:["ForgeInject"])]

Quick Start

1. Register dependencies

import ForgeInject
structAppDependencies:ForgeRegisterProtocol{func registerDependencies(in container:ForgeContainerProtocol){
container.register(with:.singleton){ _ inNetworkService()asNetworkServiceProtocol}
container.register(with:.singleton){ _ inUserRepository()asUserRepositoryProtocol}}}

2. Bootstrap at app launch

import SwiftUI
import ForgeInject
@mainstructTaskFlowApp:App{init(){letcontainer=ForgeContainer()AppDependencies().registerDependencies(in: container)ForgeContainer.shared = container
}varbody:someScene{WindowGroup{ContentView()}}}

3. Inject dependencies

import ForgeInject
@Injectable@ObservablefinalclassProfileViewModel{letnetwork:NetworkServiceProtocolletrepository:UserRepositoryProtocolvaruser:User?func loadProfile()async{
user =try?await repository.fetchCurrentUser()}}
// Production — zero-arg init resolves from the container
letvm=ProfileViewModel()
// Tests — pass mocks directly, no container touching
letvm=ProfileViewModel(
network:MockNetworkService(),
repository:MockUserRepository())

Which macro to use

@Injectable — start here. Generates a matching init with default values resolved from ForgeContainer.shared. Tests override dependencies via normal init arguments — no container manipulation required.

@InjectablefinalclassImageProcessor{letfilter:FilterServiceletstorage:StorageService}

@Inject — lazy, cached, thread-safe. Use for heavy dependencies, circular dependency breaks, or late-bootstrapped services.

finalclassAdvancedViewModel{@InjectvarheavyService:HeavyService // lazy (default)
@Inject(lazy:false)varlogger:LoggerService // eager, no Mutex overhead
}

#inject() — freestanding, works anywhere a value is expected. Local variables, default parameters, lazy var initializers.

structRequestHandler{letdatabase:Database= #inject()func handle()async{letlogger:Logger= #inject()
logger.info("handling request")}}

See the Macros section above for when to use which.

Retain policies

// Singleton — shared for the container's lifetime
container.register(with:.singleton){ _ inDatabaseService()asDatabaseServiceProtocol}
// Transient — new instance every resolve
container.register(with:.transient){ _ inFormValidator()}
// Weak — shared while held, recreated after release
container.register(with:.weak){ _ inImageCache()asImageCacheProtocol}

The Forge Family

ForgeInject is part of the Forge family of Swift packages for iOS.

PackageDescription
ForgeCoreThread-safe primitives for iOS Swift packages.
ForgeInjectDependency injection with constructor and property wrapper support.
ForgeObserversReactive system observers — connectivity, lifecycle, keyboard, and more.
ForgeStorageType-safe key-value, file, and Keychain storage.
ForgeDBType-safe repository pattern and GRDB-backed SQLite persistence.
ForgeOrchestratorOrchestrate app flows — startup gates, data pipelines, and continuous monitors.
ForgePushPush notification management — permissions, tokens, and routing.
ForgeLocationLocation triggers — geofencing, significant changes, and visits.
ForgeBackgroundTasksBackground task scheduling and dispatch.
ForgeNetworkingTyped, async/await-first HTTP networking with auth, retry, and background transfers.
ForgeLogStructured logging with pluggable providers and a built-in inspector UI.
ForgeAccessSubscription-aware feature gating with override channels and debug UI.

License

ForgeInject is released under the MIT License. See LICENSE.

About

Dependency injection for iOS with constructor and property wrapper support.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages