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

SwiftUIむけに 整理された状態監視 Observation

notoroid
August 26, 2023

SwiftUIむけに 整理された状態監視 Observation

札幌iPhoneアプリ開発懇談会2023年8月セッション資料

話す内容
- Source of truth
- CombineとObservationの記述方法比較
- Observation の狙い
- Observation を実現可能としている技術

話さない内容
- データバインディング(@Binding)
- CombineとObservationの相互運用
- Observationの手動実装

お題目
- SwiftUI 5周年
- 記述方法比較 - CombineとObservation
- Observation の狙い
- まとめ

notoroid

August 26, 2023
Tweet

More Decks by notoroid

Other Decks in Programming

Transcript

  1. 4XJGU6*प೥ ϚϧνϓϥοτϑΥʔϜରԠͷ6*ϑϨʔϜϫʔΫ w 6*पΓͷॆ࣮ "OJNBUJPO 8JEHFU  w 4XJGU6*Λࢧ͑Δ࢓૊ΈͰ͋Δঢ়ଶ؂ࢹʹ͍ͭͯେ͖ͳΞοϓσʔτ w

    ʙ$PNCJOFGSBNFXPSLΛ࢖ͬͨঢ়ଶ؂ࢹΛ4XJGU6*ͱ૊Έ߹Θͤ w </FX>ʙ0CTFSWBUJPOGSBNFXPSLΛ࢖ͬͨঢ়ଶ؂ࢹͱ૊Έ߹ΘͤΔ
  2. B λά5BH import Foundation struct Tag: Identifiable { let name:

    String let value: Int var id: Int { value } } extension Array<Tag> { static func defaultTags() -> [Tag] { [.init(name: "Tag1", value: 1), .init(name: "Tag2", value: 2), .init(name: "Tag3", value: 3)] } } ᶃ*EFOUJ fi BCMFϓϩτίϧΛࢦఆ ᶄ഑ྻॳظԽ༻ͷTUBUJDؔ਺
  3. C 7JFXͷॲཧ struct ContentViewByObservationDependOnViewLifecycle: View { var tagCollection: TagCollectionByObservation =

    .init() var body: some View { VStack { Button { let newTagValue = tagCollection.collectionCount + 1 tagCollection.collection.append( .init(name: "Tag\(newTagValue)", value: newTagValue) ) } label: { Text("Add") } Text("Tag number:\(tagCollection.collectionCount)") List(tagCollection.collection) { tag in Label( title: { Text("\(tag.name)") }, icon: { Image(systemName: "tag.fill") } ) } .listStyle(.plain) } .padding() } } ᶃ7JFXͰ͸એݴʹҧ͍͋Γ ᶄϘλϯΛλοϓ͢Δͱ 5BH͕૿͑Δ͚ͩ
  4. D σʔλιʔεΛ഑ஔ͢Δ"QQ import SwiftUI @main struct ObservationCombineCodeComparisonApp: App { @StateObject

    var tagCollectionByCombine: TagCollectionByCombine = .init() var tagCollectionByObservation:TagCollectionByObservation = .init() var body: some Scene { … } } @StateObject var tagCollectionByCombine: TagCollectionByCombine = .init() var tagCollectionByObservation:TagCollectionByObservation = .init() $PNCJOF </FX>0CTFSWBUJPO ᶃঢ়ଶର৅ʹࢦఆ͢Δ4XJGU"UUSJCVUFT ᶄಛʹهड़ͳ͠
  5. E σʔλιʔεΦϒδΣΫτ $PNCJOF </FX>0CTFSWBUJPO import Foundation class TagCollectionByCombine: ObservableObject {

    @Published var collection: [Tag] = .defaultTags() var collectionCount: Int { collection.count } } import Observation @Observable class TagCollectionByObservation { var collection: [Tag] = .defaultTags() var collectionCount: Int { collection.count } } ᶄ!0CTFSWBCMFΛΫϥεͷલʹ෇͚Δ ᶃ0CTFSWBCMF0CKFDUͷ೿ੜΫϥε
  6. G σʔλιʔεΛ؍ଌ͢Δଆͷఆٛ $PNCJOF </FX>0CTFSWBUJPO struct ContentViewByCombineFromParameter: View { @ObservedObject var

    tagCollection: TagCollectionByCombine } struct ContentViewByCombineFromEmvironment: View { @EnvironmentObject var tagCollection: TagCollectionByCombine } struct ContentViewByObservationFromParameter: View { var tagCollection: TagCollectionByObservation } struct ContentViewByObservationFromEmvironment: View { @Environment(TagCollectionByObservation.self) var tagCollection: } ᶃҾ਺Ͱ౉͞ΕΔ৔߹ ᶄ؀ڥม਺Ͱ౉͞ΕΔ৔߹ ᶅ؀ڥม਺Ͱ౉͞ΕΔ৔߹ͷΈࢦఆ
  7. struct ContentViewDependOnViewLifecycle: View { @StateObject var tagCollection: TagCollectionByCombine = .init()

    } H 7JFXͷม਺ͱͯ͠ಠཱͯ͠࢖͏ $PNCJOF </FX>0CTFSWBUJPO ᶃม਺ఆٛͰ͸!4UBUF0CKFDU͕ඞཁ struct ContentViewByObservationDependOnViewLifecycle: View { var tagCollection: TagCollectionByObservation = .init() } ᶄಛʹࢦఆͳ͠
  8. $PNCJOFͱ0CTFSWBUJPOͷҧ͍ هड़͢ΔՕॴ͸ͦΕ΄ͲมΘΒͣ $PNCJOF 0CTFSWBUJPO ϑϨʔϜϫʔΫ 'PVOEBUJPO $PNCJOF͸ඪ४ѻ͍ 0CTFSWBUJPO σʔλιʔεͷఆٛ !4UBUF0CKFDU

    ಛʹͳ͠ σʔλιʔεͷએݴ 0CTFSWBCMF0CKFDUͷ೿ੜΫϥε ؍ଌ͍ͤͨ͞ଐੑʹ!1VCMJTIFEࢦఆ Ϋϥεͷઌ಄ʹ!0CTFSWBCMF Կ΋ࢦఆ͠ͳ͍ͱ؍ଌ͢Δଐੑʹ σʔλιʔεΛ؍ଌ͢Δ ଆͷఆٛ !0CTFSWFE0CKFDU !&OWJSPONFOU0CKFDU ؀ڥม਺Ͱ౉͞ΕΔ৔߹ͷΈ !&OWJSPONFOU σʔλόΠϯσΟϯά ৗʹ༗ޮ !#JOEBCMFΛࢦఆ͠ͳ͍ͱ༗ޮ ʹͳΒͳ͍
  9. $PNCJOF ʙ Ͱ͸γϯϓϧʹ࣮ݱͰ͖ͳ͍͜ͱ͕ଟ͍ w σʔλ؍ଌͷͨΊʹ4XJGU"UUSJCVUFTΛ෇Ճ͢Δඞཁ͕͋Δ w !4UBUF0CKFDUɺ!0CTFSWFE0CKFDUɺ!&OWJSPONFOU0CKFDU w ഑ྻ ू߹Λ͞Βʹू߹

    Λͦͷ··σʔλ؍ଌର৅ʹͰ͖ͳ͍ w 4XJGU6*Ͱ஋ΛऔΓѻ͏4XJGU"UUSJCVUFTͱিಥ͍ͯ͠Δ w !4UBUF w !"QQ4UPSBHF w !4DFOF4UPSFBHF
  10. ഑ྻ ू߹Λ͞Βʹू߹ Λͦͷ··σʔλ؍ଌର৅ʹ $PNCJOF </FX>0CTFSWBUJPO @main struct ObservationCombineCodeComparisonApp: App {

    @StateObject var tagCollectionByCombine: [TagCollectionByCombine] = .init() } ΤϥʔͱͳΔ @main struct ObservationCombineCodeComparisonApp: App { var tagCollectionByObservation:[TagCollectionByObservation] = .init() } Τϥʔʹ͸ͳΒͣͦΕͧΕ؍ ଌՄೳͳσʔλΦϒδΣΫτ ͱͯ͠ػೳ
  11. 4XJGU6*Ͱ஋ΛऔΓѻ͏4XJGU"UUSJCVUFTͱিಥ͍ͯ͠Δ w !4UBUF w !"QQ4UPSBHF w !4DFOF4UPSFBHF ᶃ7JFX಺Ͱঢ়ଶ؂ࢹͰ͖Δม਺ʹࢦఆ ᶄΞϓϦͷετϨʔδ͔Βσʔλऔಘ ᶅγʔϯͷण໋಺Ͱ༗ޮͳσʔλ͔Βࢀর

    σʔλ؍ଌͷͨΊ͚ͩʹ4XJGU"UUSJCVUFTΛ઎༗͞ΕΔͱଞͷ༻్ͷ 4XJGU"UUSJCVUFTͷ࢖༻Λ๦͓͛ͯΓճආࡦͷͨΊͷίʔυهड़͕ඞཁ import Foundation class TagCollectionByCombine: ObservableObject { @Published var collection: [Tag] = .defaultTags() var collectionCount: Int { collection.count } }
  12. 0CTFSWBUJPOొ৔ͷഎܠ w 4XJGU6*ެ։࣌ ʙ  w $PNCJOF w 4XJGU"UUSJCVUFT w

    Ϋϥε೿ੜ w 4XJGU.BDSPT  ొ৔ w 0CTFSWBUJPOʹΑΔσʔλ؍ଌͷ࢓૊ΈΛ࣮ݱ w ա౓ʹ4XJGU"UUSJCVUFTґଘ͠ͳ͘ͳͬͨ
  13. ࢀߟ w %JTDPWFS0CTFSWBUJPOJO4XJGU6*88%$ 7JEFPT"QQMF%FWFMPQFS w IUUQTEFWFMPQFSBQQMFDPNXXED w ʲ88%$ʳ%JTDPWFS0CTFSWBUJPOJO4XJGU6*ʢ೔ຊ ޠ༁ʣJ1IPOFΞϓϦ։ൃߨ࠲ʛ$PEF$BOEZΦϯϥΠ ϯϓϩάϥϛϯάεΫʔϧ

    w IUUQTCMPHDPEFDBOEZDPN EJTDPWFS@PCTFSWBUJPO@JO@TXJGUVJ w ͞Α͏ͳΒɺ$PNCJOFɻͦͯ͜͠Μʹͪ͸ɺ 0CTFSWBUJPOɻ2JJUB w IUUQTRJJUBDPNMPWFFJUFNT ECCBCCD w 8IBU`TOFXJO4XJGU88%$7JEFPT"QQMF %FWFMPQFS w IUUQTEFWFMPQFSBQQMFDPNXXED UJNF w %BUB'MPX5ISPVHI4XJGU6*88%$7JEFPT "QQMF%FWFMPQFS w IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZ XXED UJNF w "QQMF͕ ΍Γ͍ͨ์୊4XJGU"UUSJCVUFT4QFBLFS %FDL w IUUQTTQFBLFSEFDLDPNOPUPSPJEBQQMFHB ZBSJUBJGBOHUJTXJGUBUUSJCVUFT w Αͤ͋ͭΊ4XJGU4XJGU4QFBLFS%FDL w IUUQTTQFBLFSEFDLDPNOPUPSPJE ZPTFBUVNFTXJGUTXJGUEPU