Welcome to the documentation for SwiftInjection!
SwiftInjection is a lightweight dependency injection framework written in Swift. It provides a way to manage dependencies between different components of an application, making it easier to write modular and testable code.
There are several benefits to using SwiftInjection in your projects:
- Modularity: SwiftInjection helps in breaking down your code into smaller, more manageable parts. It allows you to define dependencies between these parts, making it easier to reason about the flow of your application.
- Testability: With SwiftInjection, you can easily replace dependencies with mock objects during unit testing. This enables you to write comprehensive tests for each component of your application.
- Flexibility: SwiftInjection provides a flexible way to manage dependencies. It supports different types of injection, such as property injection and constructor injection, giving you full control over how components interact with each other.
Getting Started
Installation
To use SwiftInjection in your project, you need to install it using Swift Package Manager (SPM).
```shell $ swift package init ```
Add the following dependency to your `Package.swift` file:
```swift .package(url: "https://github.com/your-repo/SwiftInjection.git", from: "1.0.0"), ```
Then, update your target’s dependencies:
```swift .target(name: "YourTarget", dependencies: ["SwiftInjection"]), ```
Usage
Here’s a step-by-step guide to help you get started with SwiftInjection:
Step 1: Create Your Components
In SwiftInjection, components are classes or structs that represent the different parts of your application. You can define your components as follows:
```swift class MyService { func doSomething() { // Implementation } } class MyViewController { var service: MyService? func viewDidLoad() { super.viewDidLoad() service?.doSomething() } } ```
Step 2: Define Dependencies
To define dependencies between your components, you need to create a `Container` instance. This container will hold references to your components and handle the injection process. Here’s an example:
```swift let container = Container() container.register(MyService.self) { _ in MyService() } container.register(MyViewController.self) { resolver in let viewController = MyViewController() viewController.service = resolver.resolve(MyService.self) return viewController } ```
Step 3: Resolve Dependencies
To resolve dependencies, you can use the `resolve` method of the `Container` instance. It will automatically inject the required dependencies for you. Here’s an example:
```swift let viewController = container.resolve(MyViewController.self) ```
Step 4: Use Your Components
Now that you have resolved your dependencies, you can start using your components. For example:
```swift viewController.viewDidLoad() ```
Advanced Usage
Property Injection
SwiftInjection supports property injection, which allows you to inject dependencies directly into properties of your components. To use property injection, you can use the `@Inject` property wrapper provided by SwiftInjection. Here’s an example:
```swift class MyViewController { @Inject var service: MyService? func viewDidLoad() { super.viewDidLoad() service?.doSomething() } } ```
Constructor Injection
SwiftInjection also supports constructor injection, which allows you to inject dependencies through the initializer of your components. To use constructor injection, you need to pass the dependencies as parameters to the initializer. Here’s an example:
```swift class MyViewController { let service: MyService init(service: MyService) { self.service = service } func viewDidLoad() { super.viewDidLoad() service.doSomething() } } ```
Named Dependencies
If you have multiple implementations of the same protocol or class, you can use named dependencies to differentiate between them. Here’s an example:
```swift protocol MyProtocol {} class MyImplementationA: MyProtocol {} class MyImplementationB: MyProtocol {} let container = Container() container.register(MyProtocol.self, name: "A") { _ in MyImplementationA() } container.register(MyProtocol.self, name: "B") { _ in MyImplementationB() } let componentA = container.resolve(MyProtocol.self, name: "A") let componentB = container.resolve(MyProtocol.self, name: "B") ```
Scopes
SwiftInjection provides different scopes for managing the lifecycle of your components:
- Transient: The default scope, where a new instance of a component is created every time it is resolved.
- Singleton: A single instance of a component is created and reused every time it is resolved.
- Weak: Similar to the singleton scope, but the component is weakly referenced. If the component is deallocated, a new instance will be created on the next resolve.
To specify a scope for a component, you can use the `inScope` method of the registration. Here’s an example:
```swift container.register(MyService.self) { _ in MyService() }.inScope(.singleton) ```
Resolving Optional Dependencies
If a dependency is optional, you can use the `resolveOptional` method of the `Container` instance to resolve it. This method returns an optional value. Here’s an example:
```swift let optionalService = container.resolveOptional(MyService.self) ```
Conclusion
Congratulations! You have successfully learned the basics of using SwiftInjection for dependency injection in your projects. Remember to explore the official documentation for more in-depth information and advanced usage.