How to make a simple resolver in Swift
Issue #25
The Marvel world
Ant Man
We know Ant Man is Hank Pym
1 | struct AntManSuit { |
Everytime HankPym is created, he always uses the Ant Man suit. This time he is so coupled to the role Ant Man
More suits
Well, he does not have to be too dependent on the Ant Man suit. We know Hank Pym is a genius scientist, he has more suits to use. Let’s make it decoupled
Using Dependency Injection
1 | protocol Suit { |
Now Hank Pym can be more flexible on which suit to use.
Dependency Injection
The technique we just saw is called Dependency Injection
, in which Hank Pym does not need to create the Suit, it will be provided through constructor or property.
Dependency Inversion Principle
In the first example, Hank Pym is dependent on the concrete implementation of the Suit
In the second example, both Hank Pym and the suits are dependent on the Suit protocol. This way Hank Pym only knows about the Suit protocol, and future suits must be crafted to that it conforms to the Suit protocol
This way the dependency is inverted
High level modules should not depend upon low level modules. Both should depend upon abstractions.
What is the high level policy? It is the abstractions that underlie the application, the
truths that do not vary when the details are changed
Inversion of Control Container
You may ask yourself Why is Inversion of Control named that way?
Framework vs library
People said “the framework calls you but you call the library”
Command line vs GUI
See What is Inversion of Control?
For example, in an old school menu, you might have:
1 | print "enter your name" |
thereby controlling the flow of user interaction.
In a GUI program or some such, instead we say
1 | when the user types in field a, store it in NAME |
You how have a brief understanding of how IoC means
IoC container
In the 2nd example of the Suit protocol, you can see how there is a inversion of control. What if there is a container that contains all the Suit conformances?
Let’s use my Resolver
1 | let resolver = Resolver() |
Quite helpful, right? :]
Features
Actually, IoC container helps you more than that.
- Circular Dependency Injection
- Auto Injection
- Object Scope
- …
There are some IoC containers in Swift
Swinject
1 | let container = Container() |
Swinject requires explicit type declaration. It has SwinjectStoryboard, which helps configuring the dependency for your view controller
Dip
Dip leverages generic and encourage protocols
1 | container.register { ServiceImp() as Service } |
You ‘ll learn a lot just by reading Dip source code, on how factory and factory type are stored and checked using generic
1 | public func resolve<T, F>(tag tag: Tag? = nil, builder: F->T) throws -> T { |
Build your own simple IoC container
You may have discovered, that the idea of all those framework is to use closure as factory method
1 | let factory = { |
All we have to do is to store these factories closure
Take a look at my gist SimpleResolver.swift
1 | class SimpleResolver { |