Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dependency Injection in Swift

Dependency Injection in Swift

Presentation at Tokyo iOS Meetup on February 13, 2016.

http://www.meetup.com/TokyoiOSMeetup/events/226293873/

Yoichi Tagaya

February 13, 2016
Tweet

More Decks by Yoichi Tagaya

Other Decks in Programming

Transcript

  1. Dependency Injection in Scala http://www.infoq.com/news/2015/06/play-24-dependency-injection Typesafe's Play team has released

    version 2.4 "Damiya" of their web framework... By embracing dependency injection, the refactoring towards better modularization that was started in 2.3 has continued in this release... Play has already supported dependency injection in earlier versions, but now it comes out of the box and its use is even encouraged. "Play 2.4 Moves to Dependency Injection and Java 8"
  2. Problem of Dependency: Simple Example Coupled Components class Cat {

    let name: String init(name: String) { self.name = name } func sound() -> String { return "Meow!" } } class PetOwner { let pet = Cat(name: "Mimi") func play() -> String { return "I'm playing with \(pet.name). \(pet.sound())" } } let petOwner = PetOwner() print(petOwner.play()) // prints "I'm playing with Mimi. Meow!" Hardcoded Assume we are developing a pet game...
  3. Decoupled Components protocol AnimalType { var name: String { get

    } func sound() -> String } class Cat: AnimalType { let name: String init(name: String) { self.name = name } func sound() -> String { return "Meow!" } } class PetOwner { let pet: AnimalType init(pet: AnimalType) { self.pet = pet } func play() -> String { return "I'm playing with \(pet.name). \(pet.sound())" } } let catOwner = PetOwner(pet: Cat(name: "Mimi")) print(catOwner.play()) // prints "I'm playing with Mimi. Meow!" AnimalType is Passed (Injected) Dependency to protocol not to implementation (or loosely coupled components)
  4. Decoupled Components class Dog: AnimalType { let name: String init(name:

    String) { self.name = name } func sound() -> String { return "Bow wow!" } } let dogOwner = PetOwner(pet: Dog(name: "Hachi")) print(dogOwner.play()) // prints "I'm playing with Hachi. Bow wow!" (or loosely coupled components) PetOwner can have a dog!
  5. Dependency Injection is... https://en.wikipedia.org/wiki/Dependency_injection In software engineering, dependency injection is

    a software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it. Wikipedia: Dependency injection
  6. A Bit about Inversion of Control • I'm talking to

    you.
 / You're talking to me. • You call libraries.
 / Frameworks call you. • You create what you use.
 / What you use are created (and passed).
  7. 1. Initializer Injection (Constructor Injection) class PetOwner { let pet:

    AnimalType init(pet: AnimalType) { self.pet = pet } } let catOwner = PetOwner(pet: Cat(name: "Mimi")) Preferred (No 2-step initialization)
  8. 2. Property Injection class PetOwner { var pet: AnimalType? init()

    { } } let catOwner = PetOwner() catOwner.pet = Cat(name: "Mimi") UIViewController with UIStoryboard init?(coder aDecoder: NSCoder)
  9. 3. Method Injection class PetOwner { private(set) var pet: AnimalType?

    init() { } func setPet(pet: AnimalType) { self.pet = pet } } let catOwner = PetOwner() catOwner.setPet(Cat(name: "Mimi")) class PetOwner { func play(pet: AnimalType) -> String { return "I'm playing with \(pet.name). \(pet.sound())" } } let petOwner = PetOwner() petOwner.play(Cat(name: "Mimi")) or
  10. 3. Method Injection (another pattern) struct DateManager { private let

    formatter: NSDateFormatter = { let formatter = NSDateFormatter() formatter.dateStyle = .MediumStyle return formatter }() func today(date: NSDate = NSDate()) -> String { return formatter.stringFromDate(date) } } let dateManager = DateManager() // Production print(dateManager.today()) // prints "Feb 13, 2016" // Test XCTAssertEqual( "Jan 1, 1970", dateManager.today(NSDate(timeIntervalSince1970: 0.0))) Date can be injected for test
  11. DI (Dependency Injection) Container Examples: • Spring (Java/Scala) • Dagger

    (Java/Scala) • Guice (Java/Scala) • Ninject (C#) Popular in Java or static languages. Less popular in Ruby or dynamic languages. What's DI Container?
  12. Problem: Soon You'll See Dependency Graph /FUXPSL $MBTT" Reference %BUBCBTF

    5JNF 4USVDU# $MBTT$ Easy way to manage the dependency graph???
  13. DI Container /FUXPSL $MBTT" %BUBCBTF 5JNF 4USVDU# $MBTT$ Dependency graph

    %*$POUBJOFS Register at the beginning Resolve when you need *OTUBODFPG $MBTT"
  14. DI Container for Swift import Swinject let container = Container()

    container.register(AnimalType.self) { _ in Cat(name: "Mimi") } container.register(PetOwner.self) { r in PetOwner(pet: r.resolve(AnimalType.self)!) } https://github.com/Swinject/Swinject Swinject let petOwner = container.resolve(PetOwner.self)! print(petOwner.play()) // prints "I'm playing with Mimi. Meow!" Registration: Resolution: Cat is instantiated automatically when PetOwner is instantiated!
  15. Summary • Dependency Injection is a pattern to decouple (loosely-couple)

    components. • DI Container stores dependency graph and provides instances upon requests. • Software architecture with Dependency Injection is easier to test, maintain and organize.