Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
SwiftUI Viewの責務分離
Search
elmetal
PRO
February 18, 2025
Programming
550
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
SwiftUI Viewの責務分離
elmetal
PRO
February 18, 2025
More Decks by elmetal
See All by elmetal
プロダクトコードからライブラリの境界を見つける
elmetal
PRO
0
110
SwiftUI Text Rendering Deep Dive
elmetal
PRO
0
51
The Integrity of Making: Extending Xcode Previews with MCP
elmetal
PRO
0
48
Generating DocC with AI
elmetal
PRO
0
78
A Swift Way to Blog
elmetal
PRO
0
260
Designing DocC for Clarity and Beauty
elmetal
PRO
0
150
サイボウズiOSアプリのマルチモジュール 2024
elmetal
PRO
0
160
開発を加速する共有Swift Package実践
elmetal
PRO
0
1.5k
Resolve Nested ObservableObject issues in Observation
elmetal
PRO
0
460
Other Decks in Programming
See All in Programming
残高管理から台帳サービスへの進化
artoy
0
180
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
400
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
320
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
470
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5k
Jetpack Compose Mechanisms
skydoves
2
670
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
260
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
350
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
160
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
140
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
160
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
55
10k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
280
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
870
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
400
The SEO identity crisis: Don't let AI make you average
varn
0
580
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
260
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.9k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Transcript
4XJGU6*7JFXͷ .PCJMF"$504"," FMNFUBM
"CPVUNF !FM@NFUBM@ J04"QQ %FWFMPQFS ڝഅ ରઓήʔϜ ҭࣇ ෳνʔϜͷ ٕज़ࢧԉ
4XJGU6*7JFXେ͖͘ͳΓ͕ͪ
ͨͩͷϦετ struct ContentView: View { @State var pokemons: [Pokemon] =
[Pokemon(name: "Sprigatito"), Pokemon(name: "Fuecoco"), Pokemon(name: "Quaxly")] var body: some View { NavigationView { PokemonList(data: pokemons) .listStyle(.grid) } } }
αʔόʔ͔ΒσʔλΛGFUDI͢Δ struct ContentView: View { @State var pokemons: [Pokemon] =
[] var body: some View { NavigationView { PokemonList(data: pokemons) .listStyle(.grid) .task { do { pokemons = try await PokeRepository.mock.fetch() } catch { // some errors } } } } }
σʔλ͕݅ͷέʔεΛՃ struct ContentView: View { @State var pokemons: [Pokemon] =
[] var body: some View { NavigationView { if pokemons.isEmpty { Text("no pokemons") } else { PokemonList(data: pokemons) .listStyle(.grid) } } .task { do { pokemons = try await PokeRepository.mock.fetch() } catch { // some errors } } } }
௨৴ΤϥʔͷέʔεΛՃ struct ContentView: View { @State var pokemons: [Pokemon] =
[] @State var error: MyError? var body: some View { NavigationView { if let error { switch error { case .network: Text("network error") } } else if pokemons.isEmpty { Text("no pokemons") } else { PokemonList(data: pokemons) .listStyle(.grid) } } .task { do { pokemons = try await PokeRepository.mock.fetch() self.error = nil } catch { self.error = .network } } } }
ओཁ෦͕͍ΒΕ͍ͯ͘ struct ContentView: View { @State var pokemons: [Pokemon] =
[] @State var error: MyError? var body: some View { NavigationView { if let error { switch error { case .network: Text("network error") } } else if pokemons.isEmpty { Text("no pokemons") } else { PokemonList(data: pokemons) .listStyle(.grid) } } .task { do { pokemons = try await PokeRepository.mock.fetch() self.error = nil } catch { self.error = .network } } } } ओཁ෦͜Ε͚ͩ
7JFXͷׂ
ίʔφʔέʔεΛ struct ContentView: View { @State var pokemons: [Pokemon] =
[] @State var error: MyError? var body: some View { NavigationView { PokemonList(data: pokemons) .listStyle(.grid) .task { do { pokemons = try await PokeRepository.mock.fetch() self.error = nil } catch { self.error = .network } } .overlay { if let error { switch error { case .network: Text("network error") } } else if pokemons.isEmpty { Text("no pokemons") } } } } } ΤϥʔΛPWFSMBZϒϩοΫ
$POUFOU6OBWBJMBCMF7JFXΛར༻ struct ContentView: View { @State var pokemons: [Pokemon] =
[] @State var error: MyError? var body: some View { NavigationView { PokemonList(data: pokemons) .listStyle(.grid) .task { do { pokemons = try await PokeRepository.mock.fetch() self.error = nil } catch { self.error = .network } } .overlay { if let error { switch error { case .network: ContentUnavailableView("network error", systemImage: "wifi.slash", description: Text("check your internet connection")) } } else if pokemons.isEmpty { ContentUnavailableView("no pokemons", systemImage: "circle") } } } } } ۭྻ ωοτϫʔΫΤϥʔ
ۭྻͷදࣔఆٛଆͰߦ͏ struct GridPokeListStyle: PokeListStyle { var columns = [GridItem(.adaptive(minimum: 80),
spacing: 16)] func makeBody(configuration: PokeListConfiguration) -> some View { ScrollView { LazyVGrid(columns: columns, spacing: 16) { ForEach(configuration.pokemons, id: \.self) { pokemon in PokemonView(pokemon: pokemon) } } .padding([.horizontal], 16) } .overlay { if configuration.pokemons.isEmpty { ContentUnavailableView("no pokemons", systemImage: "circle") } } } }
ۭྻͷදࣔఆٛଆͰߦ͏ struct ContentView: View { @State var pokemons: [Pokemon] =
[] @State var error: MyError? var body: some View { NavigationView { PokemonList(data: pokemons) .listStyle(.grid) .task { do { pokemons = try await PokeRepository.mock.fetch() self.error = nil } catch { self.error = .network } } .overlay { if let error { switch error { case .network: ContentUnavailableView("network error", systemImage: "wifi.slash", description: Text("check your internet connection")) } } } } } }
એ
4XJGU6*7JFX$PEJOH(VJEFMJOFT https://github.com/cybozu/swiftui-view-coding-guidelines https://cybozu.github.io/swiftui-view-coding-guidelines/documentation/swiftuiviewcodingguidelines/ %PD$ (JU)VC3FQP
2"
͋Γ͕ͱ͏͍͟͝·ͨ͠