Slide 1

Slide 1 text

Pure DI ೖ໳ DevSapษڧձ 19/01/26

Slide 2

Slide 2 text

ੁݪ ༞ @yusuga_

Slide 3

Slide 3 text

DI࢖ͬͯ·͔͢ʁ • Dependency Injection (DI) • ґଘΦϒδΣΫτͷ஫ೖ • ͦͷଞͷΩʔϫʔυͱͯ͠DIίϯςφ • iOS։ൃऀͳΒ99.9%࢖ͬͨ͜ͱ͋ΔσβΠϯύλʔϯ

Slide 4

Slide 4 text

ґଘͱ͸ • ʮΫϥεAΛਖ਼͘͠ಈ͔͢ͷʹΫϥεB͕ඞཁʯͱ͍͏ঢ়ଶͳΒ ʮΫϥεA͸ΫϥεBʹґଘ͍ͯ͠Δʯͱݴ͑Δ

Slide 5

Slide 5 text

ґଘΦϒδΣΫτͷ஫ೖํ๏ • ίϯετϥΫλɾΠϯδΣΫγϣϯ • SwiftͳΒΠχγϟϥΠβʔɾΠϯδΣΫγϣϯ • ηολʔɾΠϯδΣΫγϣϯ

Slide 6

Slide 6 text

ྫ • ڞ௨ͷఆٛ protocol Service { func requestUsers() } class Twitter: Service { func requestUsers() { /* Twitter API */ } } class Instagram: Service { func requestUsers() { /* Instagram API */ } }

Slide 7

Slide 7 text

DIͳ͠ class UsersViewController: UIViewController { let service = Twitter() // UsersViewController͸Twitterʹґଘ͍ͯ͠Δ func reload() { service.requestUsers() } } let vc = UsersViewController() vc.reload() // ΋͠΋ґଘΛInstagramʹม͍͑ͨ৔߹͸௚઀ίʔυΛฤू͢Δඞཁ͕͋Δ

Slide 8

Slide 8 text

ίϯετϥΫλɾΠϯδΣΫγϣϯ 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() } }

Slide 9

Slide 9 text

ίϯετϥΫλɾΠϯδΣΫγϣϯ let vc = UsersViewController(service: Twitter()) let vc = UsersViewController(service: Instagram())

Slide 10

Slide 10 text

ηολʔɾΠϯδΣΫγϣϯ class UsersViewController: UIViewController { var service: Service? func reload() { service?.requestUsers() } } let vc = UsersViewController() vc.service = Twitter() // ηολʔͰґଘΦϒδΣΫτΛ஫ೖ vc.reload()

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

IBOutlet͸ηολʔɾΠϯδΣΫγϣϯͰղܾ͞ΕΔ class UsersViewController: UIViewController { // Storyboard(or Xib)͔ΒΠϯδΣΫγϣϯ͞ΕΔ @IBOutlet weak var button: UIButton! } • ͨͩ͠ɺxmlϑΝΠϧͱΫϥε಺ͷએݴ͕Ұகͯ͠ͳ͔ͬͨΒϥ ϯλΠϜͰΫϥογϡ͢Δ • ޙड़͢ΔಈతDIίϯςφͷσϝϦοτ

Slide 14

Slide 14 text

DIͱ͸ • DIͱ͍͏༻ޠΛ஌Βͳ͍ਓͰ΋࢖ͬͨ͜ͱ͋ΔσβΠϯύλʔ ϯ • iOS։ൃऀͳΒIBOutlet͸99.9%࢖ͬͨ͜ͱ͋Δʢ͸ͣ • Α͘࿩୊ʹ্͕ΔDIͷ࿩͸ɺϥΠϒϥϦΛ࢖ͬͯ؆୯ʹDI͠Α ͏ͱ͍͏࿩

Slide 15

Slide 15 text

DIίϯςφͱ͸ • DIίϯςφ͸ґଘؔ܎ΛղܾͰ͖ΔΦϒδΣΫτ • Storyboard΍Xib͸ಈతDIίϯςφ • ViewController΍ViewΛਖ਼͘͠ಈ࡞͢ΔͨΊͷView৘ใ΍Ϩ ΠΞ΢τͳͲͷґଘΛهड़ͨ͠xmlϑΝΠϧ • StoryboardͷΑ͏ͳDIίϯςφ͸iOS։ൃͩͱಛघͰɺίʔυͰ DIίϯςφΛ࡞੒͢Δ

Slide 16

Slide 16 text

DIͷछྨ छྨ ґଘؔ܎ͷղܾํ๏ DI (≒ Pure DI, Vanilla DI) खಈ, DIίϯςφΛ࢖༻͠ͳ͍DI ಈతDIίϯςφ DIίϯςφͰ ಈత ʹґଘؔ܎ Λղܾ ੩తDIίϯςφ DIίϯςφͰ ੩త ʹґଘؔ܎ Λղܾ

Slide 17

Slide 17 text

ओͳϥΠϒϥϦ (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࣌఺

Slide 18

Slide 18 text

Pure DIͱ͸ • Pure DI by Mark Seemann • ಈతDIίϯςφΛ࢖༻͠ͳ͍Ͱɺίϯ ύΠϧ࣌ʹ͢΂ͯͷґଘؔ܎Λ੩తʹ ղܾͤ͞ΔDI • ڧ͍੩తܕ෇͚ݴޠͷSwiftʹϚον ͍ͯ͠Δ

Slide 19

Slide 19 text

ಈతDIίϯςφͷσϝϦοτ • ಈతDIίϯςφͷ࣮૷ϛε͸ϥϯλΠϜͰ͔͠ݕ஌Ͱ͖ͳ͍ • ྫ͑͹StoryboardͱఆٛͷෆҰக͸ϥϯλΠϜͰΫϥογϡ ͯ͠ؾͮ͘ • ࣮૷ϛε͸ίϯύΠϧͷ࣌఺Ͱݕ஌ɾղܾ͍ͨ͠…

Slide 20

Slide 20 text

Pure DI in Swift • Pure • ࡞ऀ͸ReactorKitͱಉ͡ • v1.0.0 • Pure DIΛ΍Γ΍͘͢͢Δํ๏Λఏڙ͠ ͍ͯΔ͚ͩͳͷͰίʔυྔ͕গͳ͍ • ͨͩ͠αϯϓϧϓϩδΣΫτͳ͠… • ׆༻͢ΔͨΊʹ͸ҰൠతͳDIͷख๏ ͕Θ͔Βͳ͍ͱϐϯͱ͜ͳ͍͔΋͠ Εͳ͍

Slide 21

Slide 21 text

ίʔυͰൺֱղઆ • DI: खಈ • ಈతDIίϯςφ: Swinject • Pure DI: Pure

Slide 22

Slide 22 text

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() } }

Slide 23

Slide 23 text

DI: खಈʢલड़ʣ // ίϯετϥΫλɾΠϯδΣΫγϣϯ let vc = UsersViewController(service: Twitter()) vc.reload()

Slide 24

Slide 24 text

ಈత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()

Slide 25

Slide 25 text

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 /// Creates an instance of a module with a dependency and a payload. init(dependency: Dependency, payload: Payload) // ॳظԽ }

Slide 26

Slide 26 text

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() } }

Slide 27

Slide 27 text

Pure DI: Pure let factory = UsersViewController.Factory( dependency: UsersViewController.Dependency( service: Twitter() // ґଘΦϒδΣΫτ ) ) // ͜ͷfactory͸ґଘؔ܎Λղܾͨ͠FactoryΦϒδΣΫτ // ґଘؔ܎Λղܾͨ͠UsersViewControllerΛੜ੒ͯ͠ฦ͢ let vc = factory.create() vc.reload()

Slide 28

Slide 28 text

ґଘΦϒδΣΫτ + ಈతʹܾΊ͍ͨ஋

Slide 29

Slide 29 text

• 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() } }

Slide 30

Slide 30 text

DI: खಈ let vc = UsersViewController( service: Twitter(), // ґଘΦϒδΣΫτ userName: "yusuga" // ಈతʹܾΊ͍ͨ஋ ) vc.reload()

Slide 31

Slide 31 text

ಈత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()

Slide 32

Slide 32 text

஫ҙ: 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()

Slide 33

Slide 33 text

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 /// Creates an instance of a module with a dependency and a payload. init(dependency: Dependency, payload: Payload) }

Slide 34

Slide 34 text

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) } /* ҎԼলུ */ }

Slide 35

Slide 35 text

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()

Slide 36

Slide 36 text

Pure͕ఏڙ͍ͯ͠Δ΋ͷ1 • ࣄલʹܾఆͰ͖ΔґଘΦϒδΣΫτ(Dependency)Λղܾͨ͠ FactoryΫϥε let factory = UsersViewController.Factory( dependency: UsersViewController.Dependency( service: Twitter() ) ) // ͜ͷfactory͸ґଘؔ܎Λղܾͨ͠FactoryΦϒδΣΫτ

Slide 37

Slide 37 text

Pure͕ఏڙ͍ͯ͠Δ΋ͷ2 • Factory͔ΒͦͷΫϥεΛੜ੒͢Δͱ͖ʹɺಈతʹܾΊ͍ͨ஋ (Payload)ΛࢦఆͰ͖Δcreateؔ਺ let vc = factory.create( payload: UsersViewController.Payload( userName: "yusuga" ) )

Slide 38

Slide 38 text

·ͱΊ • DIͳ͠ɺDI, ಈతDIίϯςφͷ࠷ऴతʹੜ੒͞ΕΔ΋ͷ͸ಉ͡ ͰɺͦͷաఔͰґଘؔ܎ΛͲ͏͢Δ͔ͱ͍͏࿩ • ಈతDIίϯςφ͸࣮૷ϛε͸ϥϯλΠϜͰ͔͠ݕ஌Ͱ͖ͳ͍ͱ ͍͏σϝϦοτ͕͋Δ • ࣮ͨͩ૷͸ָ • Swinject͸ߴػೳͰ΄ͱΜͲͷύλʔϯΛղܾͰ͖Δ

Slide 39

Slide 39 text

·ͱΊ • ࠓճ঺հ͍ͯ͠·ͤΜ͕ɺDIKit͸ಈతDIίϯςφͷϥϯλΠϜ Ͱ͔͠ϛεΛݕ஌Ͱ͖ͳ͍෦෼Λิͬͨ ੩త DIίϯςφΛ࠾༻ • Build phasesͰιʔε಺༰͔ΒDIίϯςφΫϥεϑΝΠϧΛੜ ੒Ͱ͖ΔShell scriptΛఏڙ • ͨͩɺv0.4.0ʢ19/01/26࣌఺ʣͱ͍͏͜ͱ΋͔͋ͬͯɺ·ͩ एׯͷػೳෆ଍ײ͸͋Δ

Slide 40

Slide 40 text

·ͱΊ • Pure͸ಈతDIίϯςφΛ࢖༻ͤͣ੩తʹґଘؔ܎Λղܾͤ͞Δ ੔ཧํ๏Λఏڙ • Dependency͸ࣄલʹܾఆͰ͖ΔґଘΦϒδΣΫτɺPayload ͸ͦͷΫϥεੜ੒࣌ʹܾఆ͍ͨ͠ಈతͳ஋ͱ͍͏੔ཧํ๏ • ଞʹੜ੒࣌ʹPayload͕ܾΊΒΕͳ͍৔߹ʹ࢖༻͢Δ ConfiguratorΫϥε΋͋Δ • 2.5ਓ݄ͷϓϩδΣΫτͰಋೖͯ͠͏·͘ߦͬͨ

Slide 41

Slide 41 text

࣍ͷؔ৺ • ը໘ؒɺը໘ભҠͷґଘΛͲ͏΍ͬͯ ղܾ͢Δ͔ • RxSwiftCommunity/RxFlow • Reactive Flow Coordinator pattern • ͪ͜Β΋2.5ਓ݄ͷϓϩδΣΫτʹ࣮ઓ ౤ೖͯ͠खԠ͑͋ͬͨʢPure͚ͩͰ͸ ղܾͰ͖ͳ͍໰୊͕͋ͬͨͷͰҰॹʹ ಋೖʣ

Slide 42

Slide 42 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ