Slide 1

Slide 1 text

4XJGU6*ʹ͓͚Δ ґଘੑٯసݪଇͷઓུ f o r ୈ ճ ) " , "5" T X J G U

Slide 2

Slide 2 text

} var employedBy = "YUMEMI Inc." var job = "iOS Tech Lead" var favoriteLanguage = "Swift" var twitter = "@lovee" var qiita = "lovee" var github = "el-hoshino" var additionalInfo = """ ݘ೿ͳͷʹೣΛอޢͯ͠͠·ͬͨ """ final class Me: Developable, Talkable {

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

struct LandmarkList: View { @EnvironmentObject var modelData: ModelData @State private var showFavoritesOnly = false var body: some View { // ... } } IUUQTEFWFMPQFSBQQMFDPNUVUPSJBMTTXJGUVJ

Slide 5

Slide 5 text

final class ModelData: ObservableObject { @Published var landmarks: [Landmark] = [ // ... ] } IUUQTEFWFMPQFSBQQMFDPNUVUPSJBMTTXJGUVJ

Slide 6

Slide 6 text

LandmarkList͕ɺ ۩৅ܕͷModelDataʹґଘ͍ͯ͠Δɻ

Slide 7

Slide 7 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ final class SomeComponent { var p: Int = 0 func f() {} // ... } final class SomeObject { let component: SomeComponent init(component: SomeComponent) { self.component = component } func doSomething() { component.f() } }

Slide 8

Slide 8 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ final class SomeComponent { var p: Int = 0 func f() {} // ... } final class SomeObject { let component: SomeComponent init(component: SomeComponent) { self.component = component } func doSomething() { component.f() } } func test_doSomething() { final class MockComponent: SomeComponent { override init() { super.init() self.p = 100 } override func f() {} } let object = SomeObject(component: MockComponent()) object.doSomething() } Inheritance from a final class 'SomeComponent' Instance method overrides a 'final' instance method

Slide 9

Slide 9 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ class SomeComponent { var p: Int = 0 func f() {} // ... } final class SomeObject { let component: SomeComponent init(component: SomeComponent) { self.component = component } func doSomething() { component.f() } } func test_doSomething() { final class MockComponent: SomeComponent { override init() { super.init() self.p = 100 } override func f() {} } let object = SomeObject(component: MockComponent()) object.doSomething() } pOBMDMBTTͰએݴͰ͖ͳ͍ͨΊ ύϑΥʔϚϯε͕ඍົʹྑ͘ͳ͍ ܧঝ͕๷͛ͳ͍͔Β ࢓૊Έ্(PE$MBTT͕๷͛ͳ͍ ͦ΋ͦ΋TUSVDUͩͬͨΒͲ͏͢Δʁ ։ൃ࣌͸ΦʔόʔϥΠυશ෦Ͱ͖͚ͨͲ อक࣌ʹ௥Ճͨ͠΋ͷͷΦʔόʔϥΠυ ๨ΕͨΒͲ͏͢Δʁ

Slide 10

Slide 10 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ w ෦඼Λஔ͖׵͑ʹ͍͘ w ςετ͕ॻ͖ʹ͍͘

Slide 11

Slide 11 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ class SomeComponent { func a() {} func b() {} } final class ObjectA { let component: SomeComponent init(component: SomeComponent) { self.component = component } func doSomething() { component.a() } } final class ObjectB { let component: SomeComponent init(component: SomeComponent) { self.component = component } func doSomething() { component.b() } } 0CKFDU"͕ࣗ෼ʹෆඞཁͳ 4PNF$PNQPOFOUC Λ஌ͬͯΔ͠ 0CKFDU#΋ࣗ෼ʹෆඞཁͳ 4PNF$PNQPOFOUB Λ஌͍ͬͯΔ 4PNF$PNQPOFOUࣗମͷӨڹൣғ͕ ඇৗʹ޿ͯ͘อकੑ͕Լ͕Δ 0CKFDU"ͱ0CKFDU#΋ ࣗ෼ͨͪͲ͜·Ͱ஌Δඞཁ͕͋Δ͔ Θ͔Γʹ͍͘ͷͰอकੑ͕Լ͕Δ

Slide 12

Slide 12 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ class SomeComponent { func a() {} func b() {} } final class ObjectA { let component: SomeComponent func doSomething() { component.a() } } final class ObjectB { } func test_doSomethingA() { final class MockComponent: SomeComponent { override func a() { // } override func b() { XCTFai() } } let object = ObjectA(component: MockComponent()) object.doSomething() } B ͚ͩΦʔόʔϥΠυ͢Ε͹͍͍͸ͣͳͷʹɺ C ΋ΦʔόʔϥΠυ͠ͳͪ͘Ό͍͚ͳ͍

Slide 13

Slide 13 text

ͳͥ۩৅ʹґଘ͢Δͷ͸ѱ͍จ໌͔ w ෦඼Λஔ͖׵͑ʹ͍͘ w ςετ͕ॻ͖ʹ͍͘ w ৘ใΛ஌Γ͗͢Δ w Өڹൣғ͕޿͘อकੑ͕௿͍

Slide 14

Slide 14 text

ґଘؔ܎ٯసͷݪଇ w ্ҐϨϕϧͷϞδϡʔϧ͸ԼҐϨϕϧͷϞδϡʔϧʹ ґଘ͢΂͖Ͱ͸ͳ͍ɻ ྆ํͱ΋ந৅ʹґଘ͢΂͖Ͱ͋Δɻ w ந৅͸ৄࡉʢ۩৅ʣʹґଘͯ͠͸ͳΒͳ͍ɻ ৄࡉʢ۩৅ʣ͕ந৅ʹґଘ͢΂͖Ͱ͋Δɻ

Slide 15

Slide 15 text

۩৅ʁ ந৅ʁ

Slide 16

Slide 16 text

ந৅ protocol SomeProtocol { func add1(int: Int) -> Int } ۩৅ final class A: SomeProtocol { func add1(int: Int) -> Int { return int + 1 } } struct B: SomeProtocol { func add1(int: Int) -> Int { return int * 2 } } enum C: SomeProtocol { func add1(int: Int) -> Int { return 0 } }

Slide 17

Slide 17 text

Ԡ༻ͯ͠ΈΔͱ protocol ComponentProtocol { func f() } final class SomeObject { let component: ComponentProtocol init(component: ComponentProtocol) { self.component = component } func doSomething() { component.f() } } final class SomeComponent { var p: Int = 0 } extension SomeComponent: ComponentProtocol { func f() {} }

Slide 18

Slide 18 text

4XJGU6*ʹద༻ͯ͠ΈΔͱ protocol SomeObject: ObservableObject { var int: Int { get } } struct SomeView: View { @StateObject var object: SomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 }

Slide 19

Slide 19 text

͜ͷΑ͏ʹ4XJGU6*Ͱ΋ ґଘؔ܎Λٯసͯ͠ อकੑΛߴΊ͍ͯ͜͏

Slide 20

Slide 20 text

͜ͷΑ͏ʹ4XJGU6*Ͱ΋ ґଘؔ܎Λٯసͯ͠ อकੑΛߴΊ͍ͯ͜͏ ࢒೦ͳ͕Β ͜ΕͰऴΘΓʹͰ͖ͳ͔ͬͨ

Slide 21

Slide 21 text

4XJGU6*ʹద༻ͯ͠ΈΔͱ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @StateObject var object: SomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } Property type 'SomeObject' does not ...

Slide 22

Slide 22 text

4XJGU6*ʹద༻ͯ͠ΈΔͱ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @StateObject var object: SomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } Property type 'SomeObject' does not match that of the 'wrappedValue' property of its wrapper type 'StateObject'

Slide 23

Slide 23 text

ͳͥ@StateObjectͰprotocol͕ ͦͷ··࢖͑ͳ͍ͷ͔ w StateObjectͷwrappedValue: ObjectTypeϓϩύςΟʔ ʹΑͬͯɺ಺แ͢Δܕ͕ObjectTypeͷδΣωϦοΫܕͱͯ͠ ࢖͑Δඞཁ͕͋Δ w ObservableObjectʹ͸ObjectWillChangePublisherͱ ͍͏ؔ࿈ܕ͕એݴ͞Ε͍ͯΔͨΊɺprotocolͷଘࡏܕͱͯ͠ δΣωϦοΫܕʹͳΕͳ͍ w @StateObjectʹݶΒͣɺ@EnvironmentObject΍ @ObservedObject΋ಉ͡

Slide 24

Slide 24 text

͑ʁ͡Ό͋4XJGU6*Ͱ ґଘٯసͰ͖ͳ͍Μ͡ΌͶʁ

Slide 25

Slide 25 text

͑ʁ͡Ό͋4XJGU6*Ͱ ґଘٯసͰ͖ͳ͍Μ͡ΌͶʁ ΋ͪΖΜͰ͖·͢Αʂ

Slide 26

Slide 26 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @StateObject var object: SomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } Property type 'SomeObject' does not ...

Slide 27

Slide 27 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @StateObject var object: Object var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } δΣωϦΫεΛೖΕͯ͋͛Ε͹ 4UBUF0CKFDUʹ୅ೖͰ͖Δ

Slide 28

Slide 28 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @StateObject var object: Object var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView(object: Counter())

Slide 29

Slide 29 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @EnvironmentObject var object: Object var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView() 4UBUF0CKFDU΍0CTFSWFE0CKFDUͷ ৔߹͸໰୊ͳ͍͕ɺ &OWJSPONFOU0CKFDUͷ৔߹͸ ΠχγϟϥΠβͰδΣωϦΫε͕ ղܾͰ͖ͳ͍ͷͰɺ ໌ࣔతʹδΣωϦοΫܕΛ ॻ͘ඞཁ͕͋Δ

Slide 30

Slide 30 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol ObjectA: ObservableObject { var int: Int { get } } protocol ObjectB: ObservableObject { var string: String { get } } struct MyView: View { @EnvironmentObject var a: A @EnvironmentObject var b: B var body: some View { Text("\(a.int), \(b.string)") } } final class MyObjectA: ObjectA { @Published var int = 0 } final class MyObjectB: ObjectB { @Published var string = "" } return MyView() &OWJSPONFOU0CKFDUͷґଘ͕૿͑Δͱ δΣωϦοΫܕ΋૿͍͑ͯ͘

Slide 31

Slide 31 text

ํ๏ɿδΣωϦΫεΛ࢖͏ protocol ObjectA: ObservableObject { var int: Int { get } } protocol ObjectB: ObservableObject { var string: String { get } } struct MyView: View { @EnvironmentObject var a: A @EnvironmentObject var b: B var body: some View { Text("\(a.int), \(b.string)") } } protocol ComponentA {} final class MyObjectA: ObjectA { @ObservedObject var a: A @Published var int = 0 } protocol ComponentB {} final class MyObjectB: ObjectB { @ObservedObject var b: B @Published var string = "" } struct Component: ComponentA, ComponentB {} return MyView, MyObjectB>() &OWJSPONFOU0CKFDUͷґଘʹ΋ δΣωϦΫε͕࢖ΘΕΔͱ δΣωϦοΫܕͷωετͰ͞ΒʹΧΦε

Slide 32

Slide 32 text

ͦ΋ͦ΋@EnvironmentObject͸ ۩৅ΛӅ͢ͷʹ࢖͍͍ͨ͜ͱ΋ଟ͍ͷʹ δΣωϦΫεͰ۩৅ॻ͔͞ΕͨΒ ຊ຤స౗͡ΌΜʁ

Slide 33

Slide 33 text

ํ๏ɿܕফڈΛ࢖͏ w ܕফڈ͸ɺԿ͔ܕʹؚ·ΕΔܕม਺Λফڈ͢Δख๏ w 4XJGU6*΍$PNCJOF͚ͩͰͳ͘ɺ4XJGUϞδϡʔϧ ࣗ਎Ͱ΋ྑ͘ݟ͔͚ΒΕΔ w 4XJGU6*ɿAnyView w $PNCJOFɿAnyPublisherɺAnySubscriber w 4XJGUɿAnySequenceɺAnyCollectionʜ

Slide 34

Slide 34 text

ํ๏ɿܕফڈΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @EnvironmentObject var object: Object var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView()

Slide 35

Slide 35 text

ํ๏ɿܕফڈΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @EnvironmentObject var object: AnySomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView() δΣωϦοΫܕ͕ͳ͘ͳͬͯεοΩϦ ܕফڈͨ͠ܕΛ࢖͏ͷͰ ۩৅Λ஌Δඞཁ͕ͳ͍··

Slide 36

Slide 36 text

ͰɺͲ͏΍ͬͯܕফڈͷܕΛ ࡞Δͷʁ

Slide 37

Slide 37 text

IUUQTRJJUBDPNPNPDIJNFUBSVJUFNTECFCFG

Slide 38

Slide 38 text

ํ๏ɿܕফڈΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } private class SomeObjectBox { var int: Int { fatalError() } var objectWillChange: ObservableObjectPublisher { fatalError() } } 4UFQ ܧঝͤ͞ΔͨΊͷμϛʔΫϥεΛ࡞Δɻ ͦͷࡍΦʔόʔϥΠυͤ͞ΔͨΊͷϓϩύςΟʔ ΍ϝιουΛ࡞ΓɺGBUBM&SSPS Λฦ͢ɻ ·ͨ͜͜Ͱফڈ͍ͨ͠ܕ΋༧Ίఆ͓ٛͯ͘͠ʢࠓ ճͷ৔߹͸PCKFDU8JMM$IBOHFͷܕͰ͋Δ 0CTFSWBCMF0CKFDU0CKFDU8JMM$IBOHF1VCMJTIFS Λ0CTFSWBCMF0CKFDU1VCMJTIFSʹݻఆ͢Δʣ

Slide 39

Slide 39 text

ํ๏ɿܕফڈΛ࢖͏ private final class AnySomeObjectBox: SomeObjectBox where Object.ObjectWillChangePublisher == ObservableObjectPublisher { private let object: Object fileprivate init(_ object: Object) { self.object = object } override var int: Int { return object.int } override var objectWillChange: ObservableObjectPublisher { return object.objectWillChange } } 4UFQ μϛʔΫϥεΛܧঝͤ͞ɺܧঝͨ͠ࢠΫϥεʹ QSPUPDPM४ڌͨ͠δΣωϦοΫܕΛೖΕɺফڈ ͍ͨ͠ܕͷ੍ݶΛೖΕ͓ͯ͘ɻ ͦͷࡍɺμϛʔΫϥεͷશͯͷϓϩύςΟʔͱ ϝιουΛΦʔόʔϥΠυ͠ɺೖΕͬࢠͷ֘౰ ϓϩύςΟʔ΍ϝιουΛฦ͢ɻ

Slide 40

Slide 40 text

ํ๏ɿܕফڈΛ࢖͏ final class AnySomeObject: SomeObject { private let object: SomeObjectBox fileprivate init(_ object: O) where O.ObjectWillChangePublisher == ObservableObjectPublisher { self.object = AnySomeObjectBox(object) } var int: Int { return object.int } var objectWillChange: ObservableObjectPublisher { return object.objectWillChange } } 4UFQ QSPUPDPMʹ४ڌͨ͠ܕফڈίϯςφΫϥεΛ࡞ Γɺ಺෦ͰμϛʔΫϥεΛ࣋ͨͤΔɻ ࣮ࡍͷੜ੒࣌͸δΣωϦοΫܕΛ࣋ͬͨࢠΫϥε Ͱੜ੒ͯ࣋ͨͤ͠Δɻ ͦͯ͠QSPUPDPMͷ֤ϓϩύςΟʔ΍ϝιουΛ ೖΕͬ͜ͷͰฦ͢ɻ ͜͏͢Ε͹δΣωϦοΫܕΛ࣋ͨͳ͍μϛʔΫϥ ε͔͠ͳ͍ͷͰδΣωϦΫε͕ඞཁͳ͍ʀͰ΋Ϋ ϥεͷܧঝͱΦʔόʔϥΠυʹΑΓͪΌΜͱδΣ ωϦοΫܕΛ࣋ͬͨࢠΫϥεͷৼΔ෣͍Λ͢Δɻ

Slide 41

Slide 41 text

ํ๏ɿܕফڈΛ࢖͏ extension SomeObject where Self.ObjectWillChangePublisher == ObservableObjectPublisher { func eraseToAnySomeObject() -> AnySomeObject { return AnySomeObject(self) } } 4UFQ ར༻࣌ͷ࢖͍΍͢͞Λߟ͑ͯɺܕফڈͨ͠ίϯ ςφΫϥε΁ͷੜ੒ϝιουΛ࡞Δɻ

Slide 42

Slide 42 text

ํ๏ɿܕফڈΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @EnvironmentObject var object: AnySomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView()

Slide 43

Slide 43 text

ํ๏ɿܕফڈΛ࢖͏ protocol SomeObject: ObservableObject { var int: Int { get } } struct MyView: View { @EnvironmentObject var object: AnySomeObject var body: some View { Text("\(object.int)") } } final class Counter: SomeObject { @Published var int = 0 } return MyView() .environmentObject(Counter().eraseToAnySomeObject()) &OWJSPONFOU0CKFDUͳͷͰɺ Ͳ͜Ͱ஫ೖͯ͠΋େৎ෉ʂ

Slide 44

Slide 44 text

·ͱΊ w ॊೈͰςελϒϧͳઃܭʹґଘؔ܎ٯసͷݪଇ͸ඞਢ w 4XJGU6*Ͱ͸ґଘؔ܎ٯస͢Δͷʹ͸ͪΐͬͱେม w δΣωϦΫε΍ɺܕফڈͳͲͷख๏͕࢖͑Δ

Slide 45

Slide 45 text

δΣωϦΫε ܕফڈ ϝϦοτ ໘౗ͳ࢓૊͕ཁΒͳ͍ͷͰ ࣮૷ָ͕ ґଘͷ࣮ଶΛؾʹ͠ͳͯ͘ ࡁΉͷͰɺδΣωϦΫε͕ ཁΒͳ͍͔Βίʔυࣗମ͕ εοΩϦ͢Δ σϝϦοτ ґଘ͕૿͑ͨΓɺґଘࣗମ ΋ߋʹδΣωϦΫεΛ࢖͏ ͱॻ͖΋ಡΈ΋͠ʹ͍͘ ܕফڈͷ࢓૊ࣗମΛ࡞Δͷ ͕ඇৗʹ໘౗ ࢖͏৔໘ w 4UBUF0CKFDU΍ 0CTFSWFE0CKFDU w ґଘ͕গͳ͍ w δΣωϦΫεͷωετ͕ ਂ͘ͳ͍ w &OWJSPONFOU0CKFDUͷ ґଘ͕ଟ͍ w &OWJSPONFOU0CKFDUͷ ґଘͷδΣωϦΫεͷω ετ͕ਂ͍

Slide 46

Slide 46 text

͜ͷΑ͏ʹ4XJGU6*Ͱ΋ ґଘؔ܎Λٯసͯ͠ อकੑΛߴΊ͍ͯ͜͏

Slide 47

Slide 47 text

IUUQTZVNFNJDPOOQBTTDPNFWFOU ొஃ͓଴͓ͪͯ͠Γ·͢ʂ