# Factory for DI

In my [previous post about Dependency Injection in iOS](https://medium.com/its-tinkoff/di-in-ios-complete-guide-cd76a079d2d), I mentioned that factories can be used for DI and it's straightforward to implement. Today, we will figure out how to do it, what options are available, and why it may be more advantageous than using libraries like Swinject.

**NOTE**: In this post, I assume you are already familiar with the concept of DI (but you can learn more about it from my previous post referenced above).

# Factory pattern

The **Factory** pattern is a design pattern commonly used in software development for object creation. It encapsulates the logic for creating objects within a separate class or method, based on specific parameters or conditions.

```swift
enum ViewFactory {
    static func createView() -> UIView {
		UIView()
    }
}
let view = ViewFactory.createView()
```

It allows to extract the object creation logic from the calling point and abides by **Single Responsibility Principle**. This helps to keep the object creation logic organized and centralized, making it easier to maintain, update, and test.

The Factory pattern promotes **loose coupling** between the client code and the objects being created. Clients only depend on the factory, not on concrete classes, which allows for easier maintenance and reduces the dependencies between different parts of the codebase.

# Factory pattern for DI

Factories can be very useful for implementing DI in your application. For example, you can create a login screen with the factory and inject all required dependencies there:

```swift
protocol AuthService {}
enum AuthServiceFactory {
    static func create() -> AuthService {
		AuthServiceImpl()
    }
}
enum LoginScreenFactory {
    static func createLoginScreen() -> UIViewController {
		let authService = AuthServiceFactory.create()
		let loginVM = LoginViewModel(authService: authService)
		return LoginViewController(viewModel: viewModel)
    }
}
let loginVC = LoginScreenFactory.create()
// presenting your screen
```

As you can see, the factory creates all dependencies for this MVVM module and inject them so we have the view controller ready to present as a result.

You can use factories to create screens, services or anything you need in your application.

In smaller iOS applications, using factories can be a viable solution for DI. Factories can provide a **simple** and **lightweight** way to handle DI **without the need for external third-party** libraries or frameworks.

# When it’s not enough?

While factories can be a suitable approach for managing dependencies in smaller iOS applications, they may not be sufficient for larger, more complex projects.

In large iOS projects with numerous dependencies and complex dependency graphs, managing dependencies through factories can become more challenging. You need to **control the lifecycle** of your dependencies to manage them properly and it’s not what we have out of the box with the **factory pattern**. On top of that, it would be useful to **detect dependency cycles** and **mock dependencies easily for unit testing**. Although it is possible to implement these features, it can be tricky, especially for those not familiar with how DI containers work under the hood.

Let’s summarize what we expect from a proper DI solution and what factories actually capable of:

* **Compile-time safety**
    
    When you do DI we expect it should be compile-time safe. This means that the code will not compile if there are any errors related to dependency injection, such as missing or mismatched dependencies, or if dependencies are not registered with the container. We want to avoid runtime crashes, and this can be accomplished by avoiding runtime resolvers like Swinject. As the application grows larger, it becomes increasingly difficult to ensure that all modules use only registered dependencies.
    
* **Laziness**
    
    We want our dependencies to be lazy. It means that objects are created and initialized when they are actually needed, rather than creating and initializing all objects at once on application start. This can help improve the performance of an application, as it reduces the amount of memory and processing power required at startup. This is especially important in larger applications, where there may be a large number of objects and dependencies to manage.
    
* **Control the scope/lifecycle (+ easily reset the scope when needed)**
    
    DI container should be responsible for creating and initializing objects, managing their state during runtime, and destroying them when they are no longer needed. It can help reduce memory usage by avoiding to let unused dependencies exist in memory and releasing other system resources when they are no longer needed.
    
* **Easily mock/replace implementations for testing**
    
    We expect that we will be able to easily substitute the real dependencies of an object with test-specific dependencies, known as **mocks** or **test double**s. This can help isolate the behavior of an object or function during testing and ensure that it is functioning correctly.
    
* **Detect dependency cycles**
    
    We expect that it can identify situations where two or more objects have circular dependencies, where each object depends on another object in the cycle. This can be a problem because it can lead to infinite loops or other errors that can cause the application to crash. The larger an application grows, the more crucial it becomes.
    

Using the **Factory pattern** gives us only 2 out of 5 required features:

* ✅ Compile-time safety
    
* ✅ Laziness
    
* ❌ Control the scope/lifecycle
    
* ❌ Easily mock/replace implementations for testing
    
* ❌ Detect dependency cycles
    

How can we achieve all of them?

One option is to implement a custom solution, but a more straightforward approach is to use a ready-to-go solution. What if I tell you that the solution is a **Factory** again, but not the pattern but the **library**? - [Factory library](https://github.com/hmlongco/Factory). Created in 2022, this library takes the factory pattern to the next level which I would call **Factory pattern on steroids.**

# How to use Factory library

A simple example of using Factory:

```swift
extension Container {
    var service1: Factory<Service1> { 
        self { ServiceImpl1() }
			.singleton
    }
	var service2: Factory<Service2> { 
        self { ServiceImpl2(service1: self.service1()) }
    }
}
// you can use it like that later for DI 
let vm = ScreenViewModel(service1: Container.shared.service1(),
                         service2: Container.shared.service2())
```

Looks pretty and simple, right? You declare your dependencies as properties of the Container. You wrap your actual dependency into Factory type and simply address this property with `()` later to resolve the instance. It works due to the **callAsFunction** feature introduced in Swift 5.2.

# Features

Let’s check our requirements list again for the Factory library:

* ✅ Compile-time safety
    
    * If you declare a Factory property, you can be certain that you will be able to resolve the instance.
        
* ✅ Laziness
    
    * As you can see, we used calculated properties there, that gives as laziness.
        
* ✅ Control the lifecycle/scope
    
    * Factory [provides](https://hmlongco.github.io/Factory/documentation/factory/scopes/) us with 5 scopes: **Singleton, Cached, Shared, Graph, Unique.**
        
    * You can create your own custom scopes.
        
    * You can reset individual scope caches.
        
* ✅ Using mocks for testing is so easy
    
    * Just register the mock to update the original instance
        
    
    ```swift
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            let _ = Container.myService.register { MockService2() }
            ContentView()
        }
    }
    ```
    
* ✅ Detect dependency cycles
    
    * Factory provides the ability to catch dependency graph cycles but **only in runtime**. When your dependency will be resolved more than `dependencyChainTestMax = 8` times during one [resolution cycle](https://hmlongco.github.io/Factory/documentation/factory/cycle), the library will trigger the **fatal error**. Max value can be changed if needed.
        

On top of that, **Factory** is lightweight and easy to understand. It also provides cool `InjectedObject` property wrapper for **SwiftUI** views if you use it in your project.

# What is under the hood?

As you noticed we have a **Factory** wrapper for the closure that creates the dependency instance as a result. It provides us with some syntactic sugar. We simply ask the enclosing container to make a properly bound Factory for us using `self.callAsFunction { ... }`.

```swift
extension Container {
    var sugared: Factory<MyServiceType> { 
        self { MyService() }
    }
    var formal: Factory<MyServiceType> { 
        Factory(self) { MyService() }
    }
	// result is the same for both properties
}
```

The **Container** is basically a namespace for the factory properties you can create in the extension.

**Container** owns the **ContainerManager** instance that manages the registration and scope caching storage mechanisms for a given container.

**Factory** is just a wrapper for **FactoryRegistration** instance inside it.

**FactoryRegistration** is used internally to manage the **registration** and **resolution** process.

```swift
public struct Factory<T>: FactoryModifying {
    public init(_ container: ManagedContainer, 
				key: String = #function, 
				_ factory: @escaping () -> T) {
        self.registration = FactoryRegistration<Void,T>(id: "\(key)<\(T.self)>",
        												container: container, 
        												factory: factory)
    }
}
```

As you can see in code, **registration** **key** is a concatenation of **function name** (**property name** in this case) and **dependency type**.

**FactoryRegistration** uses the corresponding **scope** to resolve the dependency. **Scopes** are basically different types of caches (Each scope has its own level of caching).

```swift
public struct FactoryRegistration<P,T> {
    internal func resolve(with parameters: P) -> T {
		...
		return scope?.resolve(
			using: manager.cache, 
		    id: id, 
		    factory: { factory(parameters) }
		) ?? factory(parameters)
	}
}
```

**Scope** stores **factory closures** in dictionaries by **registration** **keys**:

```swift
public class Scope {
    internal func resolve<T>(using cache: Cache, id: String, factory: () -> T) -> T {
        if let cached: T = unboxed(box: cache.value(forKey: id)) {
            return cached
        }
        let instance = factory()
        if let box = box(instance) {
            cache.set(value: box, forKey: id)
        }
        return instance
    }
}
extension Scope {
    final class Cache {
        typealias CacheMap = [String: AnyBox] // Dictionary for reflection
        func value(forKey key: String) -> AnyBox? {
            cache[key]
        }
        func set(value: AnyBox, forKey key: String)  {
            cache[key] = value
        }
	}
}
```

**Factory** implementation idea is quite similar to **reflection based libraries** like **Swinject**. **Reflection** means mapping a set of **keys** to a set of **objects**. So, for example, Factory and Swinject both use a **Dictionary** to map the **keys** (instance types) to **values** of instances.

# Factory vs. Swinject

**Factory** library is similar to **Swinject** in terms of how it works under the hood. It is a **reflection-based library**.

But why then **Factory** is more preferable than **Swinject**?

The main reason to prefer **Factory** over **Swinject** is **compile-time safety**.

**Swinject** fully provides all other features that we expect from DI solution **except** **compile-time safety** and it is crucial. **Swinject** resolves instances **on demand** at **runtime** with **no safety** to avoid crashes.

On the contrary, **Factory** is **compile-time safe**.

There is a big difference in the **approach of** **how they register and resolve** instances.

When **Swinject** resolves the instance there is **no guarantee** that this instance was registered before that.

With **Factory** when you call the property as a function to resolve the instance, property declaration is already a guarantee that the instance was registered. This is why it is compile-time safe.

# Recap

To summarize, using the **Factory pattern** can be a suitable solution for **Dependency Injection** in smaller iOS applications, as it provides a simple and lightweight way to handle DI without external third-party libraries or frameworks. However, for larger and more complex projects, managing dependencies through factories can become challenging, and it may not be enough to fulfill all the requirements of proper DI. While factories can ensure compile-time safety and laziness, they cannot control the scope or lifecycle of dependencies, nor easily mock or replace implementations for testing, nor detect dependency cycles. To address these issues, one can use a ready-to-go solution such as the **Factory** library, which can provide all the required features.

**Factory pattern**

* ✅ Compile-time safety
    
* ✅ Laziness
    
* ❌ Control the lifecycle (Control the scope/ easily reset scope when needed - scopes which allow for better memory management)
    
* ❌ Easily mock/replace implementations for testing
    
* ❌ Detect dependency cycles
    

**Swinject**

* ❌ Compile-time safety
    
* ✅ Laziness
    
* ✅ Control the lifecycle
    
* ✅ Easily mock/replace implementations for testing
    
* ✅ Detect dependency cycles (but only at runtime)
    

**Factory library** - nice new approach to DI for Swift and SwiftUI

* ✅ Compile-time safety
    
* ✅ Laziness
    
* ✅ Control the lifecycle
    
* ✅ Easily mock/replace implementations for testing
    
* ✅ Detect dependency cycles (but only at runtime)
    

Thank you for reading this post, hope it was useful.
