TyphoonSwift

Powerful dependency injection for iOS & OSX working on a pure Swift

133
7
Swift

TyphoonSwift

This is alpha version. Works with Xcode 8.1 and Swift 3.

Installation

brew install appsquickly/core/typhoon

Concept

TyphoonSwift uses code generation to build your assembly. It runs as separate process (via terminal) and parses your source files on change. Once you change your assembly file and save, it parses it and generate “activated assembly” automatically.

Project setup

  • Setup typhoon to run with your Swift project

go to your project directory and run:

typhoon setup

that makes Typhoon.plist file with settings.

  • Run typhoon monitor
typhoon run
  • Add generated files to your project.

Just drag results directory to your project ( see resultDirPath inside Typhoon.plist ). It contains activated assemblies built from your assemblies and tiny typhoon runtime.

How to use

make sure that typhoon is up and running ( typhoon run command), then you can create assemblies inside your assemblies directory.
Assemblies syntax is very similar to Typhoon Objc:

class CoreComponents : Assembly {
        
    func manWith(_ name: String) -> Definition {
        return Definition(withClass: Man.self) {
            $0.injectProperty("name", with: name)
            $0.setScope(Definition.Scope.ObjectGraph)
            $0.injectProperty("brother", with: self.man())
        }
    }
    
    func man() -> Definition {
        return Definition(withClass: Man.self) { configuration in
            configuration.injectProperty("name", with: "John")
            configuration.injectProperty("brother", with: self.manWith("Alex"))
        }
    }
 
    func manWithInitializer() -> Definition {
        return Definition(withClass: Man.self) {
            $0.setScope(Definition.Scope.Prototype)
            $0.useInitializer("init(withName:)", with: { (m) in
                m.injectArgument("Tom")
            })
            $0.injectMethod("setAdultAge")
            $0.injectMethod("setValues(_:withAge:)") { (m) in
                m.injectArgument("John")
                m.injectArgument(21)
            }
        }
    }
}

After you’ve done with assemblies, you should activate Typhoon (That instantiates all eager singletones)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        Typhoon.activateAssemblies()
        return true
}

That’s all, now you can inject your components anywhere in your project, just like:

class ViewController: UIViewController {
    let man = CoreComponents.assembly.man()   
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        print("man.name=\(man.name)")
    }
}

You can resolve all your definition through
.assembly.<Definition-Method()>

Generated assembly has all your definitions methods, plus additional ways to resolve.
See examples below:


// Resovle using definition method

let man = CoreComponents.assembly.manWithInitializer()

// Get all components matching Type
let men = CoreComponents.assembly.allComponentsForType() as [Man]

// Resolve by Key
let keyedMen = CoreComponents.assembly.component(forKey: "man") as Man?

// Inject using instance type
var woman = Woman()
CoreComponents.assembly.inject(&woman)

// Resolve by Type
let byTypeWoman = CoreComponents.assembly.componentForType() as Woman?

If you still have questions how to use it, try Example project (see Example subdirectory)

Credits

  • Aleksey Garbarev - main idea and implementation
  • Igor Vasilenko - huge effort and outcome in refactoring
  • Valeriy Popov - swift2 -> swift 3 convertation. Moving dependencies to SPM
  • German Saprykin - moving SPM dependencies to separate project to keep main project untouched on SPM updates
  • You are welcome to be here 😃

TyphoonSwift is highly inspired by original Typhoon founded by Jasper Blues.

Solving circular references solution inspired by FieryCrucible DI framework.