Slide 1

Slide 1 text

4XJGU6*Ͱը໘ભҠͷঢ়ଶͱํ๏Λ 
 ؅ཧ͢ΔϧʔλΛ࡞ͬͨ࿩ f o r : 6 . & . * T X J G U ʙ ཪ J 0 4 % $ ʙ ͓ͨͩ͠קΊ͸͠ͳ͍

Slide 2

Slide 2 text

} var employedBy = "YUMEMI Inc." var job = "iOS Tech Lead" var favoriteLanguage = "Swift" var twitter = "@lovee" var qiita = "lovee" var github = "el-hoshino" var additionalInfo = """ ϒϩάॻ͘·Ͱ͕ iOSDC ͩΑʁ """ final class Me: Developable, Talkable {

Slide 3

Slide 3 text

Ұൠతͳ4XJGU6*ͷը໘ભҠ ʢ.PEBMભҠʣ struct ParentView: View { @State var showsChild = false var body: some View { Text("Parent") .fullScreenCover(isPresented: $showsChild, content: { ChildView() }) } } ભҠ੍ޚ༻ 
 .PEJ fi FS ભҠઌ ભҠϑϥά

Slide 4

Slide 4 text

Ұൠతͳ4XJGU6*ͷը໘ભҠ ʢ1VTIભҠʣ struct ParentView: View { @State var showsChild = false var body: some View { NavigationLink(destination: { ChildView() }, label: { Text("Show Child") }) } } ભҠઌ ભҠϑϥάʜʁ

Slide 5

Slide 5 text

Ұൠతͳ4XJGU6*ͷը໘ભҠ ʢ1VTIભҠʣ struct ParentView: View { @State var showsChild = false var body: some View { NavigationLink(isActive: $showsChild, destination: { ChildView() }, label: { EmptyView() }) } } ભҠઌ ભҠϑϥά ભҠ੍ޚ͕ 
 .PEJ fi FSͰ͸ͳ͍

Slide 6

Slide 6 text

Ұൠతͳ4XJGU6*ͷը໘ભҠ ʢ1VTIભҠʣ struct ParentView: View { @State var showsChild = false var body: some View { Text("Parent") .background(NavigationLink( isActive: $showsChild, destination: { ChildView() }, label: { EmptyView() } )) } } ભҠઌ ભҠϑϥά ભҠ੍ޚ༻ 
 .PEJ fi FS

Slide 7

Slide 7 text

4XJGU6*ͷը໘ભҠʹඞཁͳ৘ใ w ભҠ੍ޚ༻ͷ.PEJ fi FS w ભҠϑϥά w ભҠઌ ϧʔλ಺ ϧʔλ֎

Slide 8

Slide 8 text

3PVUFSΛ࡞Δ final class Router: ObservableObject { @Published var showsChild = false func navigationBinding() -> Binding { return .init(get: { [unowned self] in return self.showsChild }, set: { [unowned self] in self.showsChild = $0 }) } @ViewBuilder func nextView() -> some View { ChildView() } } ભҠઌ ભҠϑϥά

Slide 9

Slide 9 text

3PVUFSΛ࢖͏ struct ParentView: View { @StateObject var router = Router() var body: some View { Text("Parent") .background(NavigationLink( isActive: router.navigationBinding(), destination: { router.nextView() }, label: { EmptyView() } )) } }

Slide 10

Slide 10 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ ͳ༁͋Δ͔ʂ

Slide 11

Slide 11 text

3PVUFSΛ࢖͏ struct ParentView: View { @StateObject var router = Router() var body: some View { Text("Parent") .background(NavigationLink( isActive: router.navigationBinding(), destination: { router.nextView() }, label: { EmptyView() } )) } } 7JFX͕3PVUFSΛ׬શʹ 
 ೺Ѳ͍ͯ͠ͳ͚Ε͹ͳΒͳ͍

Slide 12

Slide 12 text

ݱঢ়ͷ໰୊఺ w Ͱ͖Ε͹7JFXଆͰ͸3PVUFSΛҰ੾஌Γͨ͘ͳ͍ w 3PVUFS͕ݺͼग़͠ݩͷ7JFXΛ೺ѲͰ͖ͳ͍ w .PEJ fi FSͰ௕͍3PVUFSద༻ίʔυॻ͘ͷ͕ͩΔ͍

Slide 13

Slide 13 text

ཧ૝ protocol ParentRouterDelegate: ObservableObject { func parentDidSubmit() } struct ParentView: View { @ObservedObject var router: R var body: some View { Button { router.parentDidSubmit() } label: { Text("Submit") } } } ໘౗ͳ࡞ۀ͸্ҐϨΠϠʔͷ͸ͣͷ 
 3PVUFSʹ೚͍ͤͨʂ

Slide 14

Slide 14 text

Ξϓϩʔν w 3PVUFSͷந৅ԽΛ෼ׂ w 7JFX͔Β΍Γ͍ͨભҠˡ7JFXʹґଘ w ભҠΛ࣮ݱ͢ΔͨΊͷ࢓૊Έˡڞ௨ϩδοΫ

Slide 15

Slide 15 text

7JFX͔Β΍Γ͍ͨભҠ protocol ParentRouterDelegate: ObservableObject { func parentDidSubmit() } struct ParentView: View { @ObservedObject var router: R // ... }

Slide 16

Slide 16 text

ભҠΛ࣮ݱ͢ΔͨΊͷ࢓૊Έ enum ViewID { //... } protocol RouterObject: ObservableObject { associatedtype NextView: View func pushFlag(for view: ViewID) -> Binding func modalFlag(for view: ViewID) -> Binding func nextView(after view: ViewID) -> NextView } struct RoutingModifier: ViewModifier { @ObservedObject var router: R var viewID: ViewID func body(content: Content) -> some View { content .background(//... .fullScreenCover(//... } } extension View { func injectRouter(_ router: R, as viewID: ViewID) -> some View { modifier(RoutingModifier(router: router, viewID: viewID)) } } ͜ΕͰݺͼग़͠ݩ͕ 
 Θ͔Δ

Slide 17

Slide 17 text

3PVUFSΛ࣮૷

Slide 18

Slide 18 text

3PVUFSͷॳظ࣮૷ final class Router: ObservableObject { @Published var parentViewRoute: ViewID? // ... func makeParentView() -> some View { ParentView(router: self) .injectRouter(self, as: .parent) } func makeChildView() -> some View { ChildView() } } 3PVUFS͕ඞཁʹԠͯ͡ 
 7JFXʹࣗ෼ࣗ਎Λ஫ೖ͢Ε͹͍͍

Slide 19

Slide 19 text

3PVUFSͷભҠ%FMFHBUFద߹ extension TestRouter: ParentRouterDelegate { func parentDidSubmit() { parentViewRoute = .child } } ભҠ͕ඞཁͳͱ͖ͷಈ࡞͚ͩΛ 
 ઐ೦Ͱ͖Δ

Slide 20

Slide 20 text

3PVUFSͷભҠ࢓૊Έͷద߹ extension TestRouter: TestRouterObject { func pushFlag(for view: ViewID) -> Binding { switch view { case .parent: return .init(get: { [unowned self] in self.parentViewRoute != nil }, set: { [unowned self] in assert($0 == false); self.parentViewRoute = nil }) case .child: return .constant(false) } } func modalFlag(for view: ViewID) -> Binding { return .constant(false) } @ViewBuilder func nextView(after view: ViewID) -> some View { switch view { case .parent: if let route = parentViewRoute, route == .child { makeChildView() } case .child: EmptyView() } } } 4XJGU6*ͷ࢓্༷ɺ 
 جຊ͜͜ݺ͹ΕΔͷ͸ 
 ໭ΔભҠ࣌ͷΈͳͷͰ ͳ͍͸ͣͷભҠ͸ 
 DPOTUBOU GBMTF Ͱ 
 ฦͤ͹͍͍ ঢ়گʹԠͯ͡ 
 7JFXΛฦ͢

Slide 21

Slide 21 text

׬੒͸͕ͨ͠ 
 Φεεϝ͸͠ͳ͍ 
 😇

Slide 22

Slide 22 text

%&.0

Slide 23

Slide 23 text

໰୊఺ w ֊૚Λލ͙1PQΞχϝʔγϣϯ͕͓͔͍͕࣌͋͠Δ w J04Ͱͦ΋ͦ΋֊૚Λލ͙1VTIભҠ͕Ͱ͖ͳ͍ w ଞʹ΋4XJGU6*ͷόά͕͋Δ͔΋͠Εͳ͍

Slide 24

Slide 24 text

ݱ࣮తʹ͸6*,JUܦ༝Ͱ 3PVUFSΛ࡞ͬͨํ͕͍͍͔΋

Slide 25

Slide 25 text

ࢀߟ IUUQTHJUIVCDPNFMIPTIJOP4XJGU6*3PVUFS%FNP