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
700
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アプリ開発ユニットテストの場合
yimajo
22
5.7k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
1.5k
不安定なテストは200種類あんねん
yimajo
3
830
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
1.8k
TCAでViewStoreにKeyPath DynamicMemberLookupが使われてる件
yimajo
0
1k
TCAでのClient/Managerの 利用パターンでは副作用のActionやErrorを分離できる
yimajo
0
810
【開催説明資料】iOSアプリ開発のための Functional Architecture 情報共有会
yimajo
0
230
SWORD ART COMBINE
yimajo
1
1.1k
iOSアプリ開発のためのThe Composable Architectureがすごく良いので紹介したい
yimajo
5
4.1k
Other Decks in Programming
See All in Programming
複雑な仕様に立ち向かうアーキテクチャ
myohei
0
170
たのしいparse.y
ydah
3
120
【re:Growth 2024】 Aurora DSQL をちゃんと話します!
maroon1st
0
770
rails statsで大解剖 🔍 “B/43流” のRailsの育て方を歴史とともに振り返ります
shoheimitani
2
930
これが俺の”自分戦略” プロセスを楽しんでいこう! - Developers CAREER Boost 2024
niftycorp
PRO
0
190
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
Effective Signals in Angular 19+: Rules and Helpers @ngbe2024
manfredsteyer
PRO
0
140
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
540
tidymodelsによるtidyな生存時間解析 / Japan.R2024
dropout009
1
770
Recoilを剥がしている話
kirik
5
6.7k
return文におけるstd::moveについて
onihusube
1
1.1k
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
190
Featured
See All Featured
Building an army of robots
kneath
302
44k
How to Think Like a Performance Engineer
csswizardry
22
1.2k
It's Worth the Effort
3n
183
28k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
Why Our Code Smells
bkeepers
PRO
335
57k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Building Adaptive Systems
keathley
38
2.3k
Making Projects Easy
brettharned
116
5.9k
Being A Developer After 40
akosma
87
590k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
66k
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ͷதͷมԽͰมߋݕͰ͖Δ