Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift 5.9 からの Observation はiOS17 未満 からも使えて stru...
Search
yimajo
February 14, 2024
Programming
2
950
Swift 5.9 からの Observation はiOS17 未満 からも使えて struct の変更検知もできるんすかね?
- @_spi(SwiftUI)の部分いついてはよくわからんので削除
-
https://x.com/yimajo/status/1774309468819579146?s=20
yimajo
February 14, 2024
Tweet
Share
More Decks by yimajo
See All by yimajo
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
2
220
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発ユニットテストの場合
yimajo
22
6.2k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
2.1k
不安定なテストは200種類あんねん
yimajo
3
970
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
1.9k
TCAでViewStoreにKeyPath DynamicMemberLookupが使われてる件
yimajo
0
1.1k
TCAでのClient/Managerの 利用パターンでは副作用のActionやErrorを分離できる
yimajo
0
880
【開催説明資料】iOSアプリ開発のための Functional Architecture 情報共有会
yimajo
0
270
SWORD ART COMBINE
yimajo
1
1.2k
Other Decks in Programming
See All in Programming
#QiitaBash MCPのセキュリティ
ryosukedtomita
1
990
iOS 26にアップデートすると実機でのHot Reloadができない?
umigishiaoi
0
130
AIともっと楽するE2Eテスト
myohei
1
390
A full stack side project webapp all in Kotlin (KotlinConf 2025)
dankim
0
110
Hack Claude Code with Claude Code
choplin
3
1k
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
110
Result型で“失敗”を型にするPHPコードの書き方
kajitack
5
610
第9回 情シス転職ミートアップ 株式会社IVRy(アイブリー)の紹介
ivry_presentationmaterials
1
290
WebViewの現在地 - SwiftUI時代のWebKit - / The Current State Of WebView
marcy731
0
110
PHPで始める振る舞い駆動開発(Behaviour-Driven Development)
ohmori_yusuke
2
350
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
1
430
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
640
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
Writing Fast Ruby
sferik
628
62k
Six Lessons from altMBA
skipperchong
28
3.9k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.7k
Building Applications with DynamoDB
mza
95
6.5k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
The World Runs on Bad Software
bkeepers
PRO
69
11k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
A better future with KSS
kneath
239
17k
Producing Creativity
orderedlist
PRO
346
40k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Building an army of robots
kneath
306
45k
Transcript
ZJNBKP 4XJGU͔Βͷ0CTFSWBUJPO J04ະຬ͔Β͑ͯ TUSVDUͷมߋݕͰ͖ΔΜ͔͢Ͷʁ
ࣗݾհʹ͔͑ͯ w αφ͖ͷϚϯγϣϯ͕͋Μ·Γͳ͍ w αφ͖ͷΪʔΫϚϯγϣϯʢখʣΛݐ͍ͯͨ w ԯ͘Β͍͍ͩ͘͞
ࣗݾհʹ͔͑ͯ w αφ͖ͷϚϯγϣϯ͕͋Μ·Γͳ͍ w αφ͖ͷΪʔΫϚϯγϣϯʢখʣΛݐ͍ͯͨ w ԯ͘Β͍͍ͩ͘͞
ຊ ࠷ۙͷษڧձͱ͔ͷࢿྉͰʜ
ʮ4XJGUҎ্ͷ0CTFSWBUJPOͰ J04Ҏ্͔ͭDMBTT͡Όͳ͍ͱมߋ ΛݕͰ·ͤΜʯ
ؒҧ͍ͬͯͳ͍͕ɺ J04Ҏ߱ͱ͔ ͦΕຊͷ͜ͱͳΜͰ͔͢ʁ
࣮ࡍ 4XJGUҎ্ͳΒ J04Ҏ্Ͱͳͯ͘ʢJ04Ҏ্ͳΒʣ 4XJGU6*Ͱ0CTFSWBUJPO͑Δ͠ TUSVDUͷࢹͰ͖ʜΔ
࣮ࡍ 4XJGUҎ্ͳΒ J04Ҏ্Ͱͳͯ͘ʢJ04Ҏ্ͳΒʣ 4XJGU6*Ͱ0CTFSWBUJPO͑Δ͠ TUSVDUͷࢹͰ͖ʜΔ ϋϐϋϐϋοϐʔ🎵 ϋοϐʙ
·ͣ 0CTFSWBUJPOͷΈͱʁ
func renderCars() { var car1 = .init() var car2 =
.init() withObservationTracking { print(car1.name) print(car2.name) } onChange: { } } XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF 044ͳBQQMFTXJGUΛਅࣅͯ͠ɺόοΫϙʔτΛ࡞ΕΔ
func renderCars() { var car1 = .init() var car2 =
.init() withObservationTracking { print(car1.name) print(car2.name) } onChange: { } } 0CTFSWBUJPO3FHJTUSBS 0CTFSWBUJPO3FHJTUSBS access XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF 044ͳBQQMFTXJGUΛਅࣅͯ͠ɺόοΫϙʔτΛ࡞ΕΔ
func renderCars() { var car1 = .init() var car2 =
.init() withObservationTracking { print(car1.name) print(car2.name) } onChange: { } } 0CTFSWBUJPO3FHJTUSBS 0CTFSWBUJPO3FHJTUSBS access @"DDFTT-JTU @"DDFTT-JTU addAccess XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF 044ͳBQQMFTXJGUΛਅࣅͯ͠ɺόοΫϙʔτΛ࡞ΕΔ
func renderCars() { var car1 = .init() var car2 =
.init() withObservationTracking { print(car1.name) print(car2.name) } onChange: { } } 0CTFSWBUJPO3FHJTUSBS 0CTFSWBUJPO3FHJTUSBS access merge @"DDFTT-JTU @"DDFTT-JTU addAccess XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF 044ͳBQQMFTXJGUΛਅࣅͯ͠ɺόοΫϙʔτΛ࡞ΕΔ
func renderCars() { var car1 = .init() var car2 =
.init() withObservationTracking { print(car1.name) print(car2.name) } onChange: { } } 0CTFSWBUJPO3FHJTUSBS 0CTFSWBUJPO3FHJTUSBS access merge @"DDFTT-JTU @"DDFTT-JTU addAccess XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF 044ͳBQQMFTXJGUΛਅࣅͯ͠ɺόοΫϙʔτΛ࡞ΕΔ
DMBTTͷมߋΛݕ͢Δࡍʹ "DDFTT-JTUʹใΛͯ͠ݕ͞Εͨ ͷ͕Կ͔͕Θ͔Δ IUUQTRJJUBDPNZJNBKPJUFNTCCDE
ͳͥ"QQMFJ04Ҏ্ ͱ͍ͯ͠Δͷ͔
J04Ҏ্ͷλʔήοτʹݶఆ͞Ε͍ͯΔ͔Β ʢNBD04 J04 XBUDI04 UW04ʣ w XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF w
0CTFSWBUJPO3FHJTUSBS
BQQMFTXJGUϦϙδτϦʹίʔυ͋Δ w XJUI0CTFSWBUJPO5SBDLJOH @PO$IBOHF w IUUQTHJUIVCDPNBQQMFTXJGUCMPCTXJGU3&-&"4&TUEMJC QVCMJD0CTFSWBUJPO4PVSDFT0CTFSWBUJPO 0CTFSWBUJPO5SBDLJOHTXJGU-- w
0CTFSWBUJPO3FHJTUSBS w IUUQTHJUIVCDPNBQQMFTXJGUCMPCTXJGU3&-&"4&TUEMJC QVCMJD0CTFSWBUJPO4PVSDFT0CTFSWBUJPO0CTFSWBUJPO3FHJTUSBSTXJGU
ͦͷ··ਅࣅͨ͠Β0CTFSWBUJPO࡞ΕΔΜ͡ΌͶʁ w όοΫϙʔτͳϥΠϒϥϦ w QPJOUGSFFDPTXJGUQFSDFQUJPO w IUUQTHJUIVCDPNQPJOUGSFFDPTXJGUQFSDFQUJPO w ଞʹ w
POFWDBU0CTFSWBUJPO#1 w IUUQTHJUIVCDPNPOFWDBU0CTFSWBUJPO#1
func renderCars() { var car1 = .init() var car2 =
.init() withPerceptionTracking { print(car1.name) print(car2.name) } onChange: { } } @"DDFTT-JTU 0CTFSWBUJPO3FHJTUSBS @"DDFTT-JTU 0CTFSWBUJPO3FHJTUSBS access merge addAccess XJUI1FSDFQUJPO5SBDLJOH @PO$IBOHF PO$IBOHFܧଓతʹಈ࡞͢ΔΘ͚͡Όͳ͍
XJUI1FSDFQUJPO5SBDLJOH @PO$IBOHF IUUQTHJUIVCDPNQPJOUGSFFDPTXJGUQFSDFQUJPOCMPCNBJO4PVSDFT1FSDFQUJPO1FSDFQUJPO5SBDLJOHTXJGU-$-
withPerceptionTracking { } onChange: { } XJUI1FSDFQUJPO5SBDLJOH @PO$IBOHF withObservationTracking {
} onChange: { } 0CTFSWBUJPO ͑Δ ͑ͳ͍ 0CTFSWBUJPO3FHJTUSBS "DDFTT-JTU 0CTFSWBUJPO
͜͜·Ͱͷ·ͱΊ "QQMFެࣜͰͳ͍#BDL1PSU͞ΕͨͷͳΒ J04͔Β͑Δʢ4XJGUҎ߱ඞਢʣ
4XJGU6*ͷ7JFX͕0CTFSWBUJPO ʹैͬͯ࠶ඳը͞ΕΔ݅
#BDL1PSUΛͬͯ4XJGU6*Ͱͦͷ··͑ΔΘ͚͡Όͳ͍ w มߋΛݕ͢Δ͜ͱͱ4XJGU6*7JFX ͕࠶ඳը͞ΕΔ݅ผ w TXJGUQFSDFQUJPOΛ4XJGU6*Ͱ ͏࣌8JUI1FSDFQUJPO5SBDLJOH Λ͏ struct SomeView:
View { var car = … var body: Some View { WithPerceptionTracking { Text(car.name) } } }
4XJGU0CTFSWBUJPO DMBTTʹ͔͑͠ͳ͍
࠷ॳʹ݁ʢ͋͘·Ͱ༧ʣ
TUSVDU͕"DDFTT-JTUΛ༻͍ͯͦͷมߋΛ௨ ͞ΕΕXJUI0CTFSWBUJPO PO$IBOHF ಈ࡞͢ΔͩΖ͏͔Βɺճ͚ͩಈ͖͑͢͞ Ε͍͍ͷͰ͋ΕͦΕ͓ͦΒ͘Մೳɻ
ͦΕͰ͖Δ͕ɺ͓ͦΒ͘ɺ 4XJGU6*7JFXΛ͏࣌TUSVDUͷΑ͏ʹίϐʔ͞ΕΔ ͷมߋ͞ΕͨͷՕॴͷ7JFXͷΈߋ৽ͱ͍͏͜ͱ Λ܁Γฦ͠ߦ͑ͳ͍ʢͣʣ
func render() { withObservationTracking { } onChange: { } }
ཧղͷͨΊɺXJUI0CTFSWBUJPO5SBDLJOHͰ4XJGU6*ߋ৽͢ΔΠϝʔδ struct SomeView: View { let car = … var body: Some View { Text(“\(car.name)”) FooView() { // userΛมߋ } } } ༧جຊͱͯ͠4XJGU6*ͷ֘7JFXҎԼΛߋ৽͍ͨ͠ɻ ͔͠͠TUSVDUͷมߋͰίϐʔ͞ΕҰҙੑ͕ͳ͘ͳΔͱɺ֘7JFXΛݟ͔ͭΒͳ͍ͷͰߋ৽Ͱ͖ͳ͍ɻ "DDFTT-JTUʹ7JFXͷ໊લΛอ͍࣋ͯ͠ΔΘ͚͡Όͳ͍ɻ
جຊ TUSVDUͷϓϩύςΟͷTFU͕ΞΫηαಈ࡞͠TFU͞Εͨ ͷ͕TFU͞ΕΔલͷͷͱผͱͯ͠ίϐʔ͞ΕΔɻ ʢJOPVUͳTUSVDU@NPEJGZΞΫηα͕ಈ࡞͠ίϐʔ ͞Εͳ͍ʣɻ
ͭ·ΓɺTUSVDUʹ!0CTFSWBCMFϚΫϩ Λར༻Ͱ͖ͯ͠·͏ͱɺ4XJGU6*ͰࠔΔ ͷͰͦͦDMBTTͷΈʹ͞Ε͍ͯΔɻ
͡Ό͋TUSVDU0CTFSWBUJPOͰ ͑ͳ͍ͷ͔ʁ
͕!0CTFSWBCMFDMBTTͳΒྑ͍ɻ ͦͷDMBTTͷϓϩύςΟʹTUSVDUͳ ͷ͕͋Δͱ͢ΔɻTUSVDUͰ͋Δϓϩύς ΟͷมߋͦͷͷΦϒδΣΫτͷมߋ ͱͯ͠ݕͰ͖Δɻ @Observable class Car { struct
Engine { var name = “V8” } @ObservationTracked var name = String() @ObservationTracked var engine = Engine() } DBSFOHJOFOBNFΛม͑ͯɺFOHJOFࣗମ͕ίϐʔ͞ΕΔɻ ݕͰ͖͍ͯΔ͕OBNF͚ͩͷมߋʹͱͲ·͍ͬͯͳ͍ɻ
͔͠͠ TUSVDUࣗମͷมߋΛݕ͍ͨ͠
IUUQTHJUIVCDPNQPJOUGSFFDPTXJGUDPNQPTBCMFBSDIJUFDUVSF 5IF$PNQPTBCMF"SDIJUFDUVSF @ObservableState struct State { @ObservationStateTracked var name =
“” } QPJOUGSFF public protocol ObservableState: Perceptible { var _$id: ObservableStateID { get } mutating func _$willModify() } IUUQTXXXQPJOUGSFFDPFQJTPEFTFQPCTFSWBCMF BSDIJUFDUVSFTUSVDUVSBMJEFOUJUZ
·ͱΊ wJ04ະຬͰެࣜͰͳ͍0CTFSWBUJPO͑Δ wDMBTT͕อ࣋͢ΔTUSVDUݕͰ͖Δ wͨͩTUSVDUͷߏͷมԽΛݕͱ͍͏͔TUSVDUࣗମͷೖΕସΘΓΛݕ w5$"ͳΒJ04ະຬ͔ͭTUSVDUͷதͷมԽͰมߋݕͰ͖Δ