Skip to content

Swift Quick Start

Jasper Blues edited this page Jan 22, 2015 · 47 revisions
let Application = Swift as TheCoursingRiver
//With all the force of a great Typhoon!

Requirements

CocoaPods install

Typhoon can be installed via CocoaPods easily. Add this to your Podfile:

pod 'Typhoon', :head

Create a YOURPROJECTNAME-Bridging-Header.h if it does not already exist and import the Typhoon Objective-C header there to use it in your Swift project.

#import "Typhoon.h"

Dynamic framework install

Typhoon can be linked against as a Dynamic Framework. Unlike the CocoaPods install, linking against Typhoon as a Dynamic Framework allows you to link in Apps and Dynamic Frameworks. Dynamic Frameworks have been around forever (Foundation, UIKit, everything Apple is a Dynamic Framework). Apple recently updated Xcode (version 6) with support to build Dynamic Framework targets (this was very difficult in the past). Dynamic Frameworks are the defacto way to ship Swift libraries, however, tooling for Dynamic Frameworks does not exist yet. Currently the best approach is to include Typhoon as a git submodule:

  1. Add Typhoon as a git submodule: git submodule add https://github.com/typhoon-framework/Typhoon.git
  2. Open your project or workspace and drag and drop the Typhoon.xcodeproj into the Project Navigator
  3. Under your projects Build Phases, add the Typhoon.framework under the Target Dependencies
  4. Under your projects Build Phases, click the + button and create a New Copy Files Phase
  5. Name the new phase Copy Frameworks
  6. Set the destination to Frameworks
  7. Click the + and add Typhoon.framework to your new copy framework phase

Simply import the Typhoon module in any Swift file that uses the framework:

import Typhoon

Setup Dependency Injection

Two following steps are required to use Dependency Injection with Typhoon:

  1. Configure TyphoonAssembly subclass(es)
  2. Use TyphoonDefinitions to tell the framework which classes should be considered for Dependency Injection

Initial setup and configuration

Create a sub-class of TyphoonAssembly, and define your class that should have a property injected (in this case we are injecting the assembly itself into the AppDelegate)

class ApplicationAssembly : TyphoonAssembly {
    
    dynamic func appDelegate() -> AnyObject {
        return TyphoonDefinition.withClass(AppDelegate.self) {
            (definition) in
            
            definition.injectProperty("assembly", with: self)
        }
    }    
}

Then create an entry TyphoonInitialAssemblies of type Array in your Info.plist and add your assembly subclass name to register the assembly:

Then, add the following property to your AppDelegate:

var assembly : ApplicationAssembly?

Definition of what should be injected into which class

Edit the ApplicationAssembly you defined above to include the following definitions. (You may need to create the classes and protocols or adjust them to your current project)

    dynamic func basicKnight() -> AnyObject {
        
        return TyphoonDefinition.withClass(Knight.self) {
            (definition) in
            
            definition.useInitializer("initWithQuest:") {
                (initializer) in
                
                initializer.injectParameterWith(self.defaultQuest())
                
            }
        }
    }
    
    dynamic func defaultQuest() -> AnyObject {
        return TyphoonDefinition.withClass(CampaignQuest.self)
    }

Now you can access the ApplicationAssembly in the AppDelegate:

   func application(application: UIApplication, 
       didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) 
       -> Bool {
        
        //Code-completion + no 'magic strings'  
        var knight : Knight = assembly.basicKnight()
        
        // . . continue setting up App        

        return true
    }

That's it!

Key Concept

Before activation each method returns a TyphoonDefinition. After activation we'll use the same interface to return built instances. In Swift, the return type of TyphoonAssembly methods must be AnyObject, to satisfy its strict type checking both before and after activation.

Other Notable Points

  • You don't need to inject the assembly into the app delegate. In fact, you can inject anything anywhere you want
  • Most of the times you will not inject the assembly itself but your classes (e.g. inject an implementation of CityDao protocol into the CitiesListViewController or similar) to have a real Dependency Injection as it was intended
  • IMPORTANT! Every class you want to inject has to be a subclass of NSObject in some way (either by subclassing or adding @objc modifier). Also if you define a protocol property in your class (e.g. var cityDao: CityDao?), that protocol must also have the @objc modifier). Otherwise injection will not work. See the sample project for more information.

Sample Application