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

Pure DI 101

Yu Sugawara
January 26, 2019

Pure DI 101

DevSap勉強会 19/01/26
https://devsap.connpass.com/event/113851/

(前回)iOSアプリのアーキテクチャについて考えてたどり着いた結論
https://speakerdeck.com/yusuga/final-conclusion-of-the-ios-architecture

Yu Sugawara

January 26, 2019
Tweet

More Decks by Yu Sugawara

Other Decks in Technology

Transcript

  1. ྫ • ڞ௨ͷఆٛ protocol Service { func requestUsers() } class

    Twitter: Service { func requestUsers() { /* Twitter API */ } } class Instagram: Service { func requestUsers() { /* Instagram API */ } }
  2. DIͳ͠ class UsersViewController: UIViewController { let service = Twitter() //

    UsersViewController͸Twitterʹґଘ͍ͯ͠Δ func reload() { service.requestUsers() } } let vc = UsersViewController() vc.reload() // ΋͠΋ґଘΛInstagramʹม͍͑ͨ৔߹͸௚઀ίʔυΛฤू͢Δඞཁ͕͋Δ
  3. ίϯετϥΫλɾΠϯδΣΫγϣϯ class UsersViewController: UIViewController { let service: Service // ґଘΦϒδΣΫτʢϓϩτίϧͰந৅Խʣ

    init(service: Service) { // ॳظԽ࣌ʹґଘΦϒδΣΫτΛ஫ೖ self.service = service super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func reload() { service.requestUsers() } }
  4. ηολʔɾΠϯδΣΫγϣϯ class UsersViewController: UIViewController { var service: Service? func reload()

    { service?.requestUsers() } } let vc = UsersViewController() vc.service = Twitter() // ηολʔͰґଘΦϒδΣΫτΛ஫ೖ vc.reload()
  5. ηολʔɾΠϯδΣΫγϣϯͷར༻γʔϯ • ίϯετϥΫλɾΠϯδΣΫγϣϯͰ͖ͳ͍৔߹ • ྫ͑͹Storyboard࢖༻࣌ let vc = UIStoryboard(name: "Main",

    bundle: nil) .instantiateInitialViewController()! as! UsersViewController vc.service = Twitter() // ηολʔͰґଘΦϒδΣΫτΛ஫ೖ
  6. IBOutlet͸ηολʔɾΠϯδΣΫγϣϯͰղܾ͞ΕΔ class UsersViewController: UIViewController { // Storyboard(or Xib)͔ΒΠϯδΣΫγϣϯ͞ΕΔ @IBOutlet weak

    var button: UIButton! } • ViewControllerΫϥεͷॳظԽޙɺґଘΦϒδΣΫτʢ্هͩͱ buttonʣ͕ࣗಈͰηολʔɾΠϯδΣΫγϣϯͰղܾ͞ΕΔ • ͳͷͰXcodeͰσϑΥϧτͰએݴ͞ΕΔܕ΋UIButton!ʹͳͬ ͍ͯΔɻ
  7. IBOutlet͸ηολʔɾΠϯδΣΫγϣϯͰղܾ͞ΕΔ class UsersViewController: UIViewController { // Storyboard(or Xib)͔ΒΠϯδΣΫγϣϯ͞ΕΔ @IBOutlet weak

    var button: UIButton! } • ͨͩ͠ɺxmlϑΝΠϧͱΫϥε಺ͷએݴ͕Ұகͯ͠ͳ͔ͬͨΒϥ ϯλΠϜͰΫϥογϡ͢Δ • ޙड़͢ΔಈతDIίϯςφͷσϝϦοτ
  8. DIͷछྨ छྨ ґଘؔ܎ͷղܾํ๏ DI (≒ Pure DI, Vanilla DI) खಈ,

    DIίϯςφΛ࢖༻͠ͳ͍DI ಈతDIίϯςφ DIίϯςφͰ ಈత ʹґଘؔ܎ Λղܾ ੩తDIίϯςφ DIίϯςφͰ ੩త ʹґଘؔ܎ Λղܾ
  9. ओͳϥΠϒϥϦ (Swift੡) ϥΠϒϥϦ Github Star DIͷछผ Swinject 2,922 ಈతDIίϯςφ Cleanse

    1,168 ಈతDIίϯςφ Dip 725 ಈతDIίϯςφ DIKit 242 ੩తDIίϯςφ Pure 186 Pure DI Github Star਺͸19/1/26࣌఺
  10. Pure DIͱ͸ • Pure DI by Mark Seemann • ಈతDIίϯςφΛ࢖༻͠ͳ͍Ͱɺίϯ

    ύΠϧ࣌ʹ͢΂ͯͷґଘؔ܎Λ੩తʹ ղܾͤ͞ΔDI • ڧ͍੩తܕ෇͚ݴޠͷSwiftʹϚον ͍ͯ͠Δ
  11. Pure DI in Swift • Pure • ࡞ऀ͸ReactorKitͱಉ͡ • v1.0.0

    • Pure DIΛ΍Γ΍͘͢͢Δํ๏Λఏڙ͠ ͍ͯΔ͚ͩͳͷͰίʔυྔ͕গͳ͍ • ͨͩ͠αϯϓϧϓϩδΣΫτͳ͠… • ׆༻͢ΔͨΊʹ͸ҰൠతͳDIͷख๏ ͕Θ͔Βͳ͍ͱϐϯͱ͜ͳ͍͔΋͠ Εͳ͍
  12. DI: खಈʢલड़ʣ class UsersViewController: UIViewController { let service: Service //

    ґଘΦϒδΣΫτ init(service: Service) { // ॳظԽ࣌ʹґଘΦϒδΣΫτΛ஫ೖ self.service = service super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func reload() { service.requestUsers() } }
  13. ಈతDIίϯςφ: Swinject let container = Container() // SwinjectͰఆٛ͞Ε͍ͯΔίϯςφΫϥε container.register(Service.self) {

    _ in Twitter() } // ServiceΛొ࿥ container.register(UsersViewController.self) { r in // UsersViewControllerΛొ࿥ UsersViewController( service: r.resolve(Service.self)! // Twitter͕ฦ͞ΕΔ ) } // ͜ͷ࣌఺Ͱcontainer͸͢΂ͯͷґଘΛղܾ͍ͯ͠Δ // containerʹొ࿥͍ͯͨ͠ґଘؔ܎Λղܾͨ͠UsersViewController͕ฦ͞ΕΔ let vc = container.resolve(UsersViewController.self)! vc.reload()
  14. PureͷఆٛʢҰ෦ʣ public protocol Module { associatedtype Dependency = Void //

    ࣄલʹܾΊΒΕΔґଘΦϒδΣΫτ associatedtype Payload = Void } /// A module that can be constructed with a factory. public protocol FactoryModule: Module { /// A factory for `Self`. associatedtype Factory = Pure.Factory<Self> /// Creates an instance of a module with a dependency and a payload. init(dependency: Dependency, payload: Payload) // ॳظԽ }
  15. Pure DI: Pure class UsersViewController: UIViewController, FactoryModule { struct Dependency

    { // ґଘΦϒδΣΫτ let service: Service } let service: Service required init(dependency: Dependency, payload: ()) { service = dependency.service super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func reload() { service.requestUsers() } }
  16. Pure DI: Pure let factory = UsersViewController.Factory( dependency: UsersViewController.Dependency( service:

    Twitter() // ґଘΦϒδΣΫτ ) ) // ͜ͷfactory͸ґଘؔ܎Λղܾͨ͠FactoryΦϒδΣΫτ // ґଘؔ܎Λղܾͨ͠UsersViewControllerΛੜ੒ͯ͠ฦ͢ let vc = factory.create() vc.reload()
  17. • UsersViewControllerͷఆٛΛগ͠มߋ class UsersViewController: UIViewController { let service: Service //

    ґଘΦϒδΣΫτ let userName: String // ಈతʹܾΊ͍ͨ஋ init(service: Service, userName: String) { self.service = service self.userName = userName super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func reload() { service.requestUsers() } }
  18. DI: खಈ let vc = UsersViewController( service: Twitter(), // ґଘΦϒδΣΫτ

    userName: "yusuga" // ಈతʹܾΊ͍ͨ஋ ) vc.reload()
  19. ಈతDIίϯςφ: Swinject let container = Container() // SwinjectͰఆٛ͞Ε͍ͯΔίϯςφΫϥε container.register(Service.self) {

    _ in Twitter() } // ServiceΛొ࿥ container.register(UsersViewController.self) { r, userName in UsersViewController( service: r.resolve(Service.self)!, // Twitter͕ฦ͞ΕΔ userName: userName // resolve࣌ʹಈతʹܾΊ͍ͨ஋͕౉͞ΕΔ ) } // ͜ͷ࣌఺Ͱcontainer͸͢΂ͯͷґଘΛղܾ͍ͯ͠Δ let vc = container.resolve( UsersViewController.self, // ґଘΦϒδΣΫτ͸ొ࿥ࡁΈ argument: "yusuga" // ಈతʹܾΊ͍ͨ஋ )! vc.reload()
  20. ஫ҙ: Swinjectͷargument͸ܕͷνΣοΫ͕ͳ͍ let container = Container() // SwinjectͰఆٛ͞Ε͍ͯΔίϯςφΫϥε container.register(Service.self) {

    _ in Twitter() } // ServiceΛొ࿥ container.register(UsersViewController.self) { r, userName in UsersViewController( service: r.resolve(Service.self)!, // Twitter͕ฦ͞ΕΔ userName: userName // resolve࣌ʹಈతʹܾΊ͍ͨ஋͕౉͞ΕΔ ) } // ͜ͷ࣌఺Ͱcontainer͸͢΂ͯͷґଘΛղܾ͍ͯ͠Δ let vc = container.resolve( UsersViewController.self, argument: 1 // userName͸Stringܕ͕ͩίϯύΠϧ͸௨Δ ) // ܕ͕ҰகͤͣґଘΛղܾͰ͖ͳ͍৔߹͸nil͕ฦΔ vc.reload()
  21. PureͷఆٛʢҰ෦ʣ public protocol Module { associatedtype Dependency = Void //

    ࣄલʹܾΊΒΕΔґଘΦϒδΣΫτ associatedtype Payload = Void // ͦͷΫϥεΛੜ੒͢Δͱ͖ʹܾΊ͍ͨಈతͳ஋ } /// A module that can be constructed with a factory. public protocol FactoryModule: Module { /// A factory for `Self`. associatedtype Factory = Pure.Factory<Self> /// Creates an instance of a module with a dependency and a payload. init(dependency: Dependency, payload: Payload) }
  22. Pure DI: Pure class UsersViewController: UIViewController, FactoryModule { struct Dependency

    { // ґଘΦϒδΣΫτ let service: Service } struct Payload { // ಈతʹܾΊ͍ͨ஋ let userName: String } let service: Service let userName: String required init(dependency: Dependency, payload: Payload) { service = dependency.service userName = payload.userName super.init(nibName: nil, bundle: nil) } /* ҎԼলུ */ }
  23. Pure DI: Pure let factory = UsersViewController.Factory( dependency: UsersViewController.Dependency( service:

    Twitter() ) ) // ͜ͷfactory͸ґଘؔ܎Λղܾͨ͠FactoryΦϒδΣΫτ // ґଘؔ܎Λղܾͨ͠UsersViewControllerΛFactory͔Βੜ੒͢Δͱ͖ʹ // PayloadʢಈతʹܾΊ͍ͨ஋ʣΛղܾ͢Δ let vc = factory.create( payload: UsersViewController.Payload( userName: "yusuga" ) ) vc.reload()
  24. ࣍ͷؔ৺ • ը໘ؒɺը໘ભҠͷґଘΛͲ͏΍ͬͯ ղܾ͢Δ͔ • RxSwiftCommunity/RxFlow • Reactive Flow Coordinator

    pattern • ͪ͜Β΋2.5ਓ݄ͷϓϩδΣΫτʹ࣮ઓ ౤ೖͯ͠खԠ͑͋ͬͨʢPure͚ͩͰ͸ ղܾͰ͖ͳ͍໰୊͕͋ͬͨͷͰҰॹʹ ಋೖʣ