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
SwiftUI Viewの責務分離
Search
elmetal
PRO
February 18, 2025
Programming
530
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
The Integrity of Making: Extending Xcode Previews with MCP
elmetal
PRO
0
38
Generating DocC with AI
elmetal
PRO
0
71
A Swift Way to Blog
elmetal
PRO
0
200
Designing DocC for Clarity and Beauty
elmetal
PRO
0
130
サイボウズiOSアプリのマルチモジュール 2024
elmetal
PRO
0
150
開発を加速する共有Swift Package実践
elmetal
PRO
0
1.4k
Resolve Nested ObservableObject issues in Observation
elmetal
PRO
0
440
ObservationSallowDive
elmetal
PRO
1
390
「サイボウズ Office」 の iOSアプリをリニューアルした話 / Renewal "Cybozu Office" iOS App
elmetal
PRO
0
760
Other Decks in Programming
See All in Programming
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.6k
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
870
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
420
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
550
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
150
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
380
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
690
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
180
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
400
メールのエイリアス機能を履き違えない
isshinfunada
0
240
PHP Application における Kubernetes 内 gRPC 通信
ganchiku
0
590
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
2
340
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
520
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
790
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Documentation Writing (for coders)
carmenintech
77
5.4k
Site-Speed That Sticks
csswizardry
13
1.4k
The Curse of the Amulet
leimatthew05
2
14k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
HDC tutorial
michielstock
2
790
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
73
41k
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"
͋Γ͕ͱ͏͍͟͝·ͨ͠