$30 off During Our Annual Pro Sale. View Details »

SwiftUI Navigation のすべて

Aikawa
September 10, 2022

SwiftUI Navigation のすべて

iOSDC Japan 2022 で発表した内容です

Aikawa

September 10, 2022
Tweet

More Decks by Aikawa

Other Decks in Programming

Transcript

  1. SwiftUI Navigation ͷ͢΂ͯ
    iOSDC Japan 2022
    kalupas226

    View Slide

  2. ࣗݾ঺հ
    • ΞΠΧϫ


    • @kalupas226


    • Cookpad Inc. iOS Developer
    2

    View Slide

  3. ΞδΣϯμ
    • SwiftUI Navigation ͷ၆ᛌ


    • ༷ʑͳछྨ ͷ Navigation


    • OS ʹΑΔมԽ͕ܹ͍͠ Navigation


    • Fire and forget / State driven Navigation API


    • SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊


    • Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔


    • ʮswiftui-navigationʯͷΞϓϩʔν


    • ·ͱΊ
    3

    View Slide

  4. 􀁟
    ຊτʔΫͰ࿩͞ͳ͍͜ͱ
    • ։ൃऀ͕ͦΕͧΕͰఆٛ͢Δಠࣗͷ Custom Navigation


    • iOS Ҏ֎ͷϓϥοτϑΥʔϜʹ͓͚Δ Navigation


    • ΞϓϦέʔγϣϯʹ͓͚Δ Navigation ͸͜͏͋Δ΂͖ͱ͍͏Α͏ͳ

    σβΠϯతͳ࿩
    4

    View Slide

  5. 􀁟
    ຊτʔΫͰओʹࢀߟʹ͍ͯ͠Δ৘ใ
    • Point-Free ੡ͷʮswiftui-navigationʯͱ͍͏ϥΠϒϥϦ


    • https://github.com/pointfreeco/swiftui-navigation


    • ൃද಺Ͱ͸ҎԼͷΑ͏ʹ۠ผͯ͠આ໌͠·͢


    • SwiftUI Navigation API: Apple ७ਖ਼ͷ API ʹ͍ͭͯͷ࿩


    • ʮswiftui-navigationʯ: ϥΠϒϥϦʹ͍ͭͯͷ࿩
    5

    View Slide

  6. SwiftUI Navigation ͷ၆ᛌ

    View Slide

  7. SwiftUI Navigation ͷ၆ᛌ
    ༷ʑͳछྨͷ Navigation

    View Slide

  8. ༷ʑͳछྨͷ Navigation API ͕ଘࡏ͢Δ
    • Tab


    • Alert


    • Sheet


    • Full Screen Cover


    • Con
    fi
    rmation Dialog


    • Popover


    • Navigation Link…
    SwiftUI Navigation ͷ၆ᛌ > ༷ʑͳछྨͷ Navigation
    8

    View Slide

  9. Tab
    TabView {
    FirstView()
    .tabItem {
    Image(systemName: "exclamationmark.circle")
    Text("Alert")
    }
    SecondView()
    .tabItem {…}
    ThirdView()
    .tabItem {…}
    FourthView()
    .tabItem {…}
    }
    SwiftUI Navigation ͷ၆ᛌ > ༷ʑͳछྨͷ Navigation

    View Slide

  10. Alert
    BaseView()
    .alert(
    “Alert͕දࣔ͞Ε·ͨ͠”,
    isPresented: $isPresentedAlert,
    actions: {
    Button("OK", action: {})
    }
    )
    SwiftUI Navigation ͷ၆ᛌ > ༷ʑͳछྨͷ Navigation

    View Slide

  11. Sheet
    BaseView()
    .sheet(
    isPresented: $isPresentedAlert,
    content: {
    Text("Sheet͕දࣔ͞Ε·ͨ͠")
    }
    )
    SwiftUI Navigation ͷ၆ᛌ > ༷ʑͳछྨͷ Navigation

    View Slide

  12. NavigationViewɾNavigationLink


    (Deprecated)
    NavigationView {
    ForEach(1...10, id: \.self) { id in
    NavigationLink(
    "Go to \(id) simple destination",
    destination: {
    Text("This is \(id) destination")
    }
    )
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > ༷ʑͳछྨͷ Navigation

    View Slide

  13. SwiftUI Navigation ͷ၆ᛌ
    OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  14. OS ͕ਐԽ͢ΔʹͭΕ API ͷܗ΋มΘ͖ͬͯͨ
    • ActionSheet API (deprecated) → Con
    fi
    rmation Dialog API


    • Alert API


    • deprecated ʹͳͬͨ΋ͷͱɺͦ͏Ͱͳ͍΋ͷ͕͋Δ


    • Navigation-base API


    • NavigationView → NavigationStack


    • NavigationLink
    14
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  15. ActionSheet API (deprecated)
    .actionSheet(isPresented: $showActionSheet) {
    ActionSheet(
    title: Text(...),
    message: Text(...),
    buttons: [
    .cancel(),
    .destructive(
    Text(...),
    action: {}
    ),
    .default(
    Text(...),
    action: {}
    )
    ]
    )
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  16. ActionSheet API (deprecated)
    .actionSheet(isPresented: $showActionSheet) {
    ActionSheet(
    title: Text(...),
    message: Text(...),
    buttons: [
    .cancel(),
    .destructive(
    Text(...),
    action: {}
    ),
    .default(
    Text(...),
    action: {}
    )
    ]
    )
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  17. ActionSheet API (deprecated)
    .actionSheet(isPresented: $showActionSheet) {
    ActionSheet(
    title: Text(...),
    message: Text(...),
    buttons: [
    .cancel(),
    .destructive(
    Text(...),
    action: {}
    ),
    .default(
    Text(...),
    action: {}
    )
    ]
    )
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  18. Con
    fi
    rmation Dialog API(iOS 15~)
    .confirmationDialog(
    “Title",
    isPresented: $isConfirming
    presenting: dialogDetail
    ) { detail in
    Button {
    } label: {
    Text("Import \(detail.name)")
    }
    Button("Cancel", role: .cancel) {
    dialogDetail = nil
    }
    } message: { detail in
    Text(\(detail.name) \(detail.type))
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  19. Con
    fi
    rmation Dialog API(iOS 15~)
    .confirmationDialog(
    “Title",
    isPresented: $isConfirming,
    presenting: dialogDetail
    ) { detail in
    Button {
    } label: {
    Text("Import \(detail.name)")
    }
    Button("Cancel", role: .cancel) {
    dialogDetail = nil
    }
    } message: { detail in
    Text(\(detail.name) \(detail.type))
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  20. Con
    fi
    rmation Dialog API(iOS 15~)
    .confirmationDialog(
    “Title",
    isPresented: $isConfirming,
    presenting: dialogDetail
    ) { detail in
    Button {
    } label: {
    Text("Import \(detail.name)")
    }
    Button("Cancel", role: .cancel) {
    dialogDetail = nil
    }
    } message: { detail in
    Text(\(detail.name) \(detail.type))
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  21. Alert API (deprecated)
    .alert(isPresented: $showAlert) {
    Alert(
    title: Text("Title"),
    message: Text("Message")
    )
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  22. Alert API (deprecated)
    .alert(item: $alertDetails) { details in
    Alert(
    title: Text("Title"),
    message: Text("""
    Imported \(details.name) \n
    Filetype: \(details.fileType).
    """),
    dismissButton: .default(Text("Dismiss"))
    )
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  23. Alert API (iOS 15~)
    .alert(
    "Alert͕දࣔ͞Ε·ͨ͠",
    isPresented: $isPresentedAlert,
    actions: {
    Button("OK", action: {})
    }
    )
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  24. NavigationViewɾOld NavigationLink (deprecated)
    NavigationView {
    List(model.notes) { note in
    NavigationLink(
    note.title,
    destination: NoteEditor(id: note.id)
    )
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  25. NavigationViewɾOld NavigationLink (deprecated)
    NavigationView {
    List(model.notes) { note in
    NavigationLink(
    note.title,
    destination: NoteEditor(id: note.id)
    )
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  26. NavigationViewɾOld NavigationLink (deprecated)
    NavigationView {
    List(model.notes) { note in
    NavigationLink(
    note.title, // ભҠݩͷ View ʹදࣔ͞ΕΔ title
    destination: NoteEditor(id: note.id) // ભҠޙͷը໘
    )
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  27. Simple NavigationStackɾNew NavigationLink
    NavigationStack {
    List(parks) { park in
    NavigationLink(
    park.name,
    value: park
    )
    }
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  28. Simple NavigationStackɾNew NavigationLink
    NavigationStack {
    List(parks) { park in
    NavigationLink(
    park.name,
    value: park
    )
    }
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  29. Simple NavigationStackɾNew NavigationLink
    NavigationStack {
    List(parks) { park in
    NavigationLink(
    park.name, // ભҠݩͷը໘ʹදࣔ͢Δ title
    value: park // ೚ҙͷܕͷ value
    )
    }
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  30. Simple NavigationStackɾNew NavigationLink
    NavigationStack {
    List(parks) { park in
    NavigationLink(
    park.name,
    value: park
    )
    }
    // value ͷܕʹԠͯ͡ navigationDestination ͕൓Ԡ͢Δ
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  31. Binding NavigationStackɾNew NavigationLink
    @State private var presentedParks: [Park] = []
    // ...
    NavigationStack(path: $presentedParks) {
    List(parks) { park in
    NavigationLink(park.name, value: park)
    }
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  32. Binding NavigationStackɾNew NavigationLink
    @State private var presentedParks: [Park] = []
    // ...
    NavigationStack(path: $presentedParks) {
    List(parks) { park in
    NavigationLink(park.name, value: park)
    }
    .navigationDestination(for: Park.self) { park in
    ParkDetails(park: park)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation

    View Slide

  33. Binding NavigationStackɾNew NavigationLink
    @State private var presentedParks: [Park] = []
    // ...
    NavigationStack(path: $presentedParks) {
    // ...
    }
    func showParks() {
    // RootView -> Park("Yosemite") -> Park("Sequoia")
    presentedParks = [Park("Yosemite"), Park("Sequoia")]
    }
    SwiftUI Navigation ͷ၆ᛌ > OS ʹΑΔมԽ͕ܹ͍͠ Navigation
    ※ iOS 16 ͷ API ʹ͍ͭͯͷ FB: https://gist.github.com/mbrandonw/f8b94957031160336cac6898a919cbb7

    View Slide

  34. SwiftUI Navigation ͷ၆ᛌ
    Fire and forget / State driven


    Navigation API

    View Slide

  35. Navigation API ͸େ͖͘ 2 ͭʹ෼ྨͰ͖Δ
    • ʮswiftui-navigationʯREADME ͔ΒҾ༻


    • Fire and forget Navigation API


    • State driven Navigation API
    35
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  36. Navigation API ͸େ͖͘ 2 ͭʹ෼ྨͰ͖Δ
    • Fire and forget Navigation API


    • State driven Navigation API
    36
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  37. Fire and forget Navigation API
    • Binding Ҿ਺ΛऔΒͳ͍


    • SwiftUI ͕ Navigation ͷঢ়ଶΛ׬શʹ಺෦Ͱ؅ཧ͢Δ


    • Navigation Λૉૣ࣮͘ݱͰ͖Δ͕ɺNavigation ʹରͯ͠

    ϓϩάϥϜతͳ੍ޚ͕Ͱ͖ͳ͘ͳΔ
    37
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  38. Fire and forget API - Tab -
    TabView {
    ReceivedView()
    .tabItem {
    // ...
    }
    SentView()
    .tabItem {
    // ...
    }
    AccountView()
    .tabItem {
    // ...
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  39. Fire and forget API - Tab -
    // Binding Ҿ਺ΛऔΒͳ͍ɻλοϓͰ͔͠ navigation Ͱ͖ͳ͍
    TabView {
    ReceivedView()
    .tabItem {
    // ...
    }
    SentView()
    .tabItem {
    // ...
    }
    AccountView()
    .tabItem {
    // ...
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  40. Fire and forget API - NavigationLink -
    NavigationView {
    List(model.notes) { note in
    NavigationLink(
    note.title,
    destination: NoteEditor(id: note.id)
    )
    }
    Text("Select a Note")
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  41. Fire and forget API - NavigationLink -
    NavigationView {
    List(model.notes) { note in
    // Binding Ҿ਺ΛऔΒͳ͍ɻλοϓͰ͔͠ navigation Ͱ͖ͳ͍
    NavigationLink(
    note.title,
    destination: NoteEditor(id: note.id)
    )
    }
    Text("Select a Note")
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  42. Navigation API ͸େ͖͘ 2 ͭʹ෼ྨͰ͖Δ
    • Fire and forget Navigation API


    • State driven Navigation API
    42
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  43. State driven Navigation API
    • Binding Ҿ਺ΛऔΔ


    • Navigation Λ༗ޮɾແޮʹ͢Δ࣌ʹυϝΠϯͷঢ়ଶ΋มߋͰ͖Δ


    • Fire and forget API ΑΓෳࡶͰ͸͋Δ͕ɺϓϩάϥϜతͳ੍ޚ͕

    ՄೳͱͳΔͨΊɺ࢖͍ํʹΑͬͯ͸ Deep Link ͳͲ΋࣮ݱͰ͖Δ
    43
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  44. State driven API - Tab -
    struct ContentView: View {
    @State var selectedTab: Tab = .received
    var body: some View {
    TabView(selection: $selectedTab) {
    ReceivedView().tabItem { ... }
    .tag(Tab.received)
    SentView().tabItem { ... }
    .tag(Tab.sent)
    AccountView().tabItem { ... }
    .tag(Tab.account)
    }
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  45. State driven API - Tab -
    struct ContentView: View {
    @State var selectedTab: Tab = .received
    var body: some View {
    TabView(selection: $selectedTab) {
    ReceivedView().tabItem { ... }
    .tag(Tab.received)
    SentView().tabItem { ... }
    .tag(Tab.sent)
    AccountView().tabItem { ... }
    .tag(Tab.account)
    }
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  46. State driven API - Tab -
    struct ContentView: View {
    @State var selectedTab: Tab = .sent
    var body: some View {
    TabView(selection: $selectedTab) {
    ReceivedView().tabItem { ... }
    .tag(Tab.received)
    SentView().tabItem { ... }
    .tag(Tab.sent)
    AccountView().tabItem { ... }
    .tag(Tab.account)
    }
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  47. ҟͳΔ View ͰแΉͱ Deep Link Ͱ͖ͳ͍
    struct ContainerView: View {
    var body: some View {
    ContentView(selectedTab: .received)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  48. ContainerView ʹঢ়ଶΛ࣋ͨͤͯղܾ͢Δʁ
    struct ContainerView: View {
    let selectedTab: Tab
    var body: some View {
    ContentView(selectedTab: selectedTab)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  49. ContainerView ʹঢ়ଶΛ࣋ͨͤͯղܾ͢Δʁ
    struct ContainerView: View {
    // ContainerView ʹؔ܎ͳ͍ Tab ͷঢ়ଶΛ࣋ͨͤΔͷ͸ඍົ
    // ͔͠΋ ContentView ͷ selectedTab ͸ @State ͳͷͰޡΓ
    let selectedTab: Tab
    var body: some View {
    ContentView(selectedTab: selectedTab)
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  50. ΞϓϦͷঢ়ଶΛ؅ཧ͢Δ ViewModel Λಋೖ͠

    ղܾ͢Δ
    class AppViewModel: ObservableObject {
    @Published var selectedTab: Tab
    init(selectedTab: Tab = .received) {
    self.selectedTab = selectedTab
    }
    }
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  51. ΞϓϦͷঢ়ଶΛ؅ཧ͢Δ ViewModel Λಋೖ͠

    ղܾ͢Δ
    struct ContentView: View {
    @ObservedObject var viewModel: AppViewModel
    var body: some View {
    TabView(selection: $viewModel.selectedTab) {
    // ...
    }
    }
    }
    // ContentView ͷ initialize ࣌ʹ Tab Λૢ࡞Ͱ͖ΔΑ͏ʹͳͬͨ
    ContentView(viewModel: .init(selectedTab: .two))
    SwiftUI Navigation ͷ၆ᛌ > Fire and forget / State driven Navigation API

    View Slide

  52. SwiftUI ͷ Navigation API

    ʹ͓͚Δ՝୊

    View Slide

  53. Navigation API ʹ͓͚Δ՝୊
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊

    View Slide

  54. Navigation API ʹ͓͚Δ՝୊
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍

    View Slide

  55. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛ


    උ͍͑ͯͳ͍
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍

    View Slide

  56. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛ


    උ͍͑ͯͳ͍
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍

    View Slide

  57. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛ


    උ͍͑ͯͳ͍
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍
    Binding ValueΛ
    EditPostViewʹ

    ౉ͤͳ͍
    EditPostViewͰͷ
    มߋ͕ContentView
    ʹ൓ө͞Εͳ͍

    View Slide

  58. Navigation API ʹ͓͚Δ՝୊
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  59. Deprecated / New Alert API
    // Deprecated API
    // Binding Λड͚औΔ
    func alert(
    isPresented: Binding,
    content: () -> Alert
    ) -> some View
    // Binding Λड͚औΔ
    func alert(
    item: Binding,
    content: (Item) -> Alert
    ) -> some View where Item : Identifiable
    // New API
    // Binding Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    actions: () -> A
    ) -> some View where A : View
    // Binding ͱ data Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    presenting data: T?,
    actions: (T) -> A
    ) -> some View where A : View
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  60. Deprecated / New Alert API
    // Deprecated API
    // Binding Λड͚औΔ
    func alert(
    isPresented: Binding,
    content: () -> Alert
    ) -> some View
    // Binding Λड͚औΔ
    func alert(
    item: Binding,
    content: (Item) -> Alert
    ) -> some View where Item : Identifiable
    // New API
    // Binding Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    actions: () -> A
    ) -> some View where A : View
    // Binding ͱ data Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    presenting data: T?,
    actions: (T) -> A
    ) -> some View where A : View
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  61. Deprecated boolean binding API
    struct ExampleView: View {
    @State private var showAlert = false
    var body: some View {
    BaseView(...)
    .alert(isPresented: $showAlert) {
    Alert(...)
    }
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  62. Deprecated / New Alert API
    // Deprecated API
    // Binding Λड͚औΔ
    func alert(
    isPresented: Binding,
    content: () -> Alert
    ) -> some View
    // Binding Λड͚औΔ
    func alert(
    item: Binding,
    content: (Item) -> Alert
    ) -> some View where Item : Identifiable
    // New API
    // Binding Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    actions: () -> A
    ) -> some View where A : View
    // Binding ͱ data Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    presenting data: T?,
    actions: (T) -> A
    ) -> some View where A : View
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  63. Deprecated optional item binding API
    struct ExampleView: View {
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(item: $item) { item in
    Alert(...) // item Λར༻ͯ͠ alert ΛΧελϚΠζͰ͖Δ
    }
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  64. Deprecated / New Alert API
    // Deprecated API
    // Binding Λड͚औΔ
    func alert(
    isPresented: Binding,
    content: () -> Alert
    ) -> some View
    // Binding Λड͚औΔ
    func alert(
    item: Binding,
    content: (Item) -> Alert
    ) -> some View where Item : Identifiable
    // New API
    // Binding Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    actions: () -> A
    ) -> some View where A : View
    // Binding ͱ data Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    presenting data: T?,
    actions: (T) -> A
    ) -> some View where A : View
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  65. New boolean binding API
    struct ExampleView: View {
    @State private var showAlert = false
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    action: { ... }
    )
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  66. Deprecated / New Alert API
    // Deprecated API
    // Binding Λड͚औΔ
    func alert(
    isPresented: Binding,
    content: () -> Alert
    ) -> some View
    // Binding Λड͚औΔ
    func alert(
    item: Binding,
    content: (Item) -> Alert
    ) -> some View where Item : Identifiable
    // New API
    // Binding Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    actions: () -> A
    ) -> some View where A : View
    // Binding ͱ data Λड͚औΔ
    func alert(
    _ title: Text,
    isPresented: Binding,
    presenting data: T?,
    actions: (T) -> A
    ) -> some View where A : View
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  67. New boolean binding and optional item API
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  68. New boolean binding and optional item API
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ
    􀁣


    showAlert: true
    item: non null

    View Slide

  69. New boolean binding and optional item API
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ
    􀁡


    showAlert: true
    item: null

    View Slide

  70. New boolean binding and optional item API ͸

    ঢ়ଶ؅ཧΛෳࡶʹͤͯ͞͠·͏
    • ։ൃऀ͕ҎԼͷঢ়ଶͷ੔߹ੑΛؾʹ͠ͳ͚Ε͹͍͚ͳ͍ͷ͕ਏ͍


    • Alert Λදࣔ͢ΔͨΊͷ boolean binding


    • Alert ͷ಺༰Λ࡞ΔͨΊͷ optional item


    • Navigation ͕γϯϓϧͳ͏ͪ͸ͦ͜·ͰࠔΒͳ͍͔΋͠Εͳ͍͕ɺ

    Navigation ͕૿͑Ε͹༰қʹঢ়ଶ؅ཧ΋ෳࡶʹͳͬͯ͠·͏
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ

    View Slide

  71. Navigation API ʹ͓͚Δ՝୊
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  72. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱ

    ແବͳঢ়ଶ͕૿͑Δ
    struct ContentView: View {
    @State var draft: Post?
    @State var settings: Settings?
    @State var userProfile: Profile?
    var body: some View {
    BaseView(...)
    .sheet(item: self.$draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    .sheet(item: self.$settings) { (settings: Settings) in
    SettingsView(settings: settings)
    }
    .sheet(item: self.$userProfile) { (userProfile: Profile) in
    UserProfile(profile: userProfile)
    }
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  73. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱ

    ແବͳঢ়ଶ͕૿͑Δ
    struct ContentView: View {
    @State var draft: Post?
    @State var settings: Settings?
    @State var userProfile: Profile?
    var body: some View {
    BaseView(...)
    .sheet(item: self.$draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    .sheet(item: self.$settings) { (settings: Settings) in
    SettingsView(settings: settings)
    }
    .sheet(item: self.$userProfile) { (userProfile: Profile) in
    UserProfile(profile: userProfile)
    }
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  74. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱ

    ແବͳঢ়ଶ͕૿͑Δ
    struct ContentView: View {
    @State var draft: Post? // null + non null = 2
    @State var settings: Settings? // null + non null = 2
    @State var userProfile: Profile? // null + non null = 2
    var body: some View {
    BaseView(...)
    .sheet(item: self.$draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    .sheet(item: self.$settings) { (settings: Settings) in
    SettingsView(settings: settings)
    }
    .sheet(item: self.$userProfile) { (userProfile: Profile) in
    UserProfile(profile: userProfile)
    }
    }
    }
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  75. ༷ʑͳύλʔϯͷঢ়ଶ͕ൃੜͯ͠͠·͏
    %SBGU 4FUUJOHT 1SP
    fi
    MF
    ύλʔϯ /VMM /VMM /VMM
    ύλʔϯ /POOVMM /VMM /VMM
    ύλʔϯ /VMM /POOVMM /VMM
    ύλʔϯ /VMM /VMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /VMM
    ύλʔϯ /POOVMM /VMM /POOVMM
    ύλʔϯ /VMM /POOVMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /POOVMM
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  76. ༷ʑͳύλʔϯͷঢ়ଶ͕ൃੜͯ͠͠·͏
    %SBGU 4FUUJOHT 1SP
    fi
    MF
    ύλʔϯ /VMM /VMM /VMM
    ύλʔϯ /POOVMM /VMM /VMM
    ύλʔϯ /VMM /POOVMM /VMM
    ύλʔϯ /VMM /VMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /VMM
    ύλʔϯ /POOVMM /VMM /POOVMM
    ύλʔϯ /VMM /POOVMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /POOVMM
    ༗ޮͳঢ়ଶ͸͜ΕΒͷΈ
    SwiftUI ͷ Navigation API ʹ͓͚Δ՝୊ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ

    View Slide

  77. Navigation API ͷ՝୊ʹ

    Ͳ͏ཱͪ޲͔͏͔

    View Slide

  78. Navigation API ʹ͓͚Δ՝୊
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔

    View Slide

  79. ʮswiftui-navigation ʯͷΞϓϩʔν
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔

    View Slide

  80. swiftui-navigation ͱ͸ʁ
    • SwiftUI ͷ Navigation ʹ focus ͨ͠ Point-Free ੡ͷϥΠϒϥϦ


    • SwiftUI ͷ Navigation Λར༻͢Δࡍͷ༷ʑͳ՝୊Λղܾ͢ΔͨΊʹҎԼͷ 3 ͭͷπʔϧΛఏڙ͍ͯ͠Δ


    • Navigation API overloads


    • ͜ͷޙ࿩͠·͢


    • Navigation views ( `IfLet`, `IfCaseLet`, `Switch`/`CaseLet` )


    • ໊લͷ௨Γͷ View ܈ɻBinding value Λѻ͑ΔΑ͏ʹઃܭ͞Ε͍ͯΔ


    • Binding transformations


    • ಠࣗͷ Navigation Λ࡞Δࡍʹ༗༻ͳπʔϧ
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔

    View Slide

  81. ʮswiftui-navigation ʯͷΞϓϩʔν
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔

    View Slide

  82. ʮswiftui-navigation ʯͷΞϓϩʔν
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  83. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛ


    උ͍͑ͯͳ͍
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  84. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛ


    උ͍͑ͯͳ͍
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads
    Binding ValueΛ
    EditPostViewʹ

    ౉ͤͳ͍
    EditPostViewͰͷ
    มߋ͕ContentView
    ʹ൓ө͞Εͳ͍

    View Slide

  85. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    }
    }
    struct EditPostView: View {
    let post: Post
    var body: some View { ... }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  86. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { ($draft: Post) in // closure ʹ Binding value Λ౉ͤΔΑ͏ʹͳͬͨΒྑͦ͞͏
    EditPostView(post: $draft)
    }
    }
    }
    struct EditPostView: View {
    @Binding var post: Post
    var body: some View { ... }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  87. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    // Binding Λ Binding ʹม׵͢Δ
    value = ???
    content(value)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  88. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    // Binding Λ Binding ʹม׵͢Δ
    value = ???
    content(value)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  89. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    // Binding Λ Binding ʹม׵͢Δ
    value = ???
    content(value)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  90. Binding Value Λ౉ͤΔ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    // Binding Λ Binding ʹม׵͢Δ
    value = ???
    content(value)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  91. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    init?(unwrapping binding: Binding) {
    guard let wrappedValue = binding.wrappedValue
    else { return nil }
    self.init(
    get: { wrappedValue },
    set: { binding.wrappedValue = $0 }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads
    ※ Binding failable initializer ͸ඪ४Ͱଘࡏ͢Δ͕ɺόά͕͋Δ: https://gist.github.com/stephencelis/3a232a1b718bab0ae1127ebd5fcf6f97

    View Slide

  92. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    init?(unwrapping binding: Binding) {
    guard let wrappedValue = binding.wrappedValue
    else { return nil }
    self.init(
    get: { wrappedValue },
    set: { binding.wrappedValue = $0 }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  93. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    init?(unwrapping binding: Binding) {
    guard let wrappedValue = binding.wrappedValue
    else { return nil }
    self.init(
    get: { wrappedValue },
    set: { binding.wrappedValue = $0 }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  94. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    init?(unwrapping binding: Binding) {
    guard let wrappedValue = binding.wrappedValue
    else { return nil }
    self.init(
    get: { wrappedValue },
    set: { binding.wrappedValue = $0 }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  95. ࡞੒ͨ͠ init?(unwrapping:) Λద༻͢Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    if let value = Binding(unwrapping: optionalValue) {
    content(value)
    }
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  96. ࡞੒ͨ͠ init?(unwrapping:) Λద༻͢Δ
    extension View {
    func sheet(
    unwrapping optionalValue: Binding,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Value: Identifiable, Content: View {
    self.sheet(item: optionalValue) { _ in
    if let value = Binding(unwrapping: optionalValue) {
    content(value)
    }
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads

    View Slide

  97. Before / After
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(unwrapping: $draft) { $draft in
    EditPostView(post: $draft)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍ > Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads
    struct ContentView: View {
    @State var draft: Post?
    var body: some View {
    Button("Edit") {
    draft = Post()
    }
    .sheet(item: $draft) { draft in
    EditPostView(post: draft)
    }
    }
    }
    #FGPSF "GUFS

    View Slide

  98. ʮswiftui-navigation ʯͷΞϓϩʔν
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads

    View Slide

  99. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads

    View Slide

  100. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    􀁣


    showAlert: true
    item: non null
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads

    View Slide

  101. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    􀁡


    showAlert: true
    item: null
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads

    View Slide

  102. ͳͥঢ়ଶ؅ཧΛෳࡶʹ͢Δ API ʹͳ͍ͬͯΔͷ͔
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert, // Alert Λදࣔ͢ΔͨΊͷ Boolean
    presenting: item // Alert ͷ಺༰ΛΧελϚΠζ͢ΔͨΊͷ optional item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  103. ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API ͸ͲΜͳܗ͔
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    title: { item in ... },
    presenting: item // optional item ͷΈͰʮalert ͷදࣔ৚݅ʯʮalertͷ಺༰ʯΛܾΊΒΕΔ
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  104. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    ???, // alert title
    isPresented: ???,
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  105. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    ???, // alert title
    isPresented: ???,
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  106. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    ???, // alert title
    isPresented: ???,
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  107. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    data.wrappedValue.map(title) ?? Text(""),
    isPresented: ???,
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  108. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    data.wrappedValue.map(title) ?? Text(""),
    isPresented: ???,
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  109. Optional item ͷΈΛཁٻ͢Δ API Λߟ͑Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    data.wrappedValue.map(title) ?? Text(""),
    isPresented: ???, // Binding Λ Binding ʹม׵Ͱ͖Δͱྑͦ͞͏
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  110. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    func isPresented() -> Binding
    where Value == Wrapped? {
    .init(
    get: { self.wrappedValue != nil },
    set: { isPresented in
    if !isPresented {
    self.wrappedValue = nil
    }
    }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  111. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    func isPresented() -> Binding
    where Value == Wrapped? { // Binding Λม׵͢ΔͨΊͷ΋ͷͳͷͰɺoptional ʹݶఆ
    .init(
    get: { self.wrappedValue != nil },
    set: { isPresented in
    if !isPresented {
    self.wrappedValue = nil
    }
    }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  112. Binding Λ Binding ʹม׵͢Δ
    extension Binding {
    func isPresented() -> Binding
    where Value == Wrapped? {
    .init(
    get: { self.wrappedValue != nil },
    set: { isPresented in
    // isPresent ͕ false = alert ͕ด͡ΒΕΔλΠϛϯά
    // ͦͷࡍ͸ Binding ࣗ਎Λ nil ʹ͢Δ͜ͱͰແޮͳঢ়ଶͷൃੜΛ๷͛Δ
    if !isPresented {
    self.wrappedValue = nil
    }
    }
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  113. ࡞੒ͨ͠ isPresented Λద༻͢Δ
    extension View {
    func alert(
    title: (T) -> Text,
    presenting data: Binding,
    @ViewBuilder actions: @escaping (T) -> A,
    @ViewBuilder message: @escaping (T) -> M
    ) -> some View {
    self.alert(
    data.wrappedValue.map(title) ?? Text(""),
    isPresented: data.isPresented(),
    presenting: data.wrappedValue,
    actions: actions,
    message: message
    )
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  114. Before / After
    struct ExampleView: View {
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    Text($0.xxx),
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    struct ExampleView: View {
    @State private var showAlert = false
    @State private var item: Item?
    var body: some View {
    BaseView(...)
    .alert(
    "Alert title",
    isPresented: $showAlert,
    presenting: item
    action: { item in ... },
    message: { item in ... }
    )
    }
    }
    #FGPSF "GUFS
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ > ঢ়ଶ؅ཧΛෳࡶʹͤ͞ͳ͍ API overloads

    View Slide

  115. ʮswiftui-navigation ʯͷΞϓϩʔν
    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • Binding value Λ౉͢͜ͱ͕Ͱ͖Δ API overloads


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ࠷௿ݶͷঢ়ଶͷΈΛཁٻ͢Δ API overloads


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  116. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱ

    ແବͳঢ়ଶ͕૿͑Δ
    struct ContentView: View {
    @State var draft: Post? // null + non null = 2
    @State var settings: Settings? // null + non null = 2
    @State var userProfile: Profile? // null + non null = 2
    var body: some View {
    BaseView(...)
    .sheet(item: self.$draft) { (draft: Post) in
    EditPostView(post: draft)
    }
    .sheet(item: self.$settings) { (settings: Settings) in
    SettingsView(settings: settings)
    }
    .sheet(item: self.$userProfile) { (userProfile: Profile) in
    UserProfile(profile: userProfile)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  117. ༷ʑͳύλʔϯͷঢ়ଶ͕ൃੜͯ͠͠·͏
    %SBGU 4FUUJOHT 1SP
    fi
    MF
    ύλʔϯ /VMM /VMM /VMM
    ύλʔϯ /POOVMM /VMM /VMM
    ύλʔϯ /VMM /POOVMM /VMM
    ύλʔϯ /VMM /VMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /VMM
    ύλʔϯ /POOVMM /VMM /POOVMM
    ύλʔϯ /VMM /POOVMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /POOVMM
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  118. ༷ʑͳύλʔϯͷঢ়ଶ͕ൃੜͯ͠͠·͏
    %SBGU 4FUUJOHT 1SP
    fi
    MF
    ύλʔϯ /VMM /VMM /VMM
    ύλʔϯ /POOVMM /VMM /VMM
    ύλʔϯ /VMM /POOVMM /VMM
    ύλʔϯ /VMM /VMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /VMM
    ύλʔϯ /POOVMM /VMM /POOVMM
    ύλʔϯ /VMM /POOVMM /POOVMM
    ύλʔϯ /POOVMM /POOVMM /POOVMM
    ༗ޮͳঢ়ଶ͸͜ΕΒͷΈ
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  119. ෳ਺ͷ Navigation ͷ࠷దͳϞσϦϯάΛߟ͑Δ
    // Navigation ͸ಉ࣌ʹෳ਺ൃੜ͢Δ͜ͱ͕ͳ͍ͨΊɺ΋ͬͱྑ͍ϞσϦϯά͕Ͱ͖ͦ͏
    @State var draft: Post?
    @State var settings: Settings?
    @State var userProfile: Profile?
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  120. ෳ਺ͷ Navigation ͷ࠷దͳϞσϦϯάΛߟ͑Δ
    // ಉ࣌ʹෳ਺ൃੜ͠ͳ͍ = enum Λ࢖͑Δ
    @State var draft: Post?
    @State var settings: Settings?
    @State var userProfile: Profile?
    "
    enum Route {
    case draft(Post)
    case settings(Settings)
    case userProfile(Profile)
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  121. enum Ͱ sheet ͳͲΛදࣔ͠Α͏ͱ͢Δͱʁ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    item: Binding(
    get: {
    if case let .draft(post) = route
    return post
    } else { return nil }
    },
    set: { post
    if let post = post {
    route = .draft(post)
    }
    }
    )
    ) { post in /* ... */ }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  122. enum Ͱ sheet ͳͲΛදࣔ͠Α͏ͱ͢Δͱʁ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    item: Binding(
    get: {
    if case let .draft(post) = route
    return post
    } else { return nil }
    },
    set: { post
    if let post = post {
    route = .draft(post)
    }
    }
    )
    ) { post in /* ... */ }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  123. enum Ͱ sheet ͳͲΛදࣔ͠Α͏ͱ͢Δͱʁ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    item: Binding(
    get: {
    if case let .draft(post) = route
    return post
    } else { return nil }
    },
    set: { post
    if let post = post {
    route = .draft(post)
    }
    }
    )
    ) { post in /* ... */ }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  124. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    unwrapping: $route,
    case: ???Route.draft???
    ) { $post in
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  125. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    unwrapping: $route, // enum ࣗମΛ౉͢ (Binding value)
    case: ???Route.draft???
    ) { $post in
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  126. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    unwrapping: $route,
    case: ???Route.draft??? // ԿΒ͔ͷܗͰ enum ͷಛఆͷ case Λࢦఆ͢Δ
    ) { $post in
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  127. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    struct ExampleView: View {
    @State private var route: Route?
    // ...
    .sheet(
    unwrapping: $route,
    case: ???Route.draft???
    ) { $post in // Associated value Λ binding value Ͱ౉ͤΔͱͳ͓ྑ͍
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  128. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: ???, // enum ͷ binding
    case: ???, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  129. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: ???, // enum ͷ binding
    case: ???, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  130. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: ???, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  131. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: ???, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  132. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: CasePath, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  133. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: CasePath, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    [CasePaths]
    • https://github.com/pointfreeco/swift-case-paths
    • struct ʹ͓͚Δ Key Paths ͷ enum ൛ͷΑ͏ͳ΋ͷ
    • Key Paths ͸ `\User.id` ͱ͢Δ͕ɺCase Paths ͸ `/Kind.animal`
    • Enum ͔Βʮಛఆͷ Case ͷநग़ʯɾʮಛఆͷ Case ΁ͷ Associated value ͷ

    ຒΊࠐΈʯΛ͍ͨ͠༻్Ͱར༻͍ͯ͠Δ

    View Slide

  134. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: CasePath, // enum ͷಛఆͷ case
    @ViewBuilder content: @escaping (Binding??>) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  135. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping: Binding, // enum ͷ binding
    case: CasePath, // enum ͷಛఆͷ case
    // AssociatedValue ͕͋Ε͹ͦΕΛར༻Ͱ͖Δ (ͳ͚Ε͹ Void) Binding
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    // ...
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  136. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: ???
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  137. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: ???
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  138. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  139. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    case(casePath) ͸ Case Paths Λར༻ͨ͠ function
    Binding ͔Β Binding Λநग़͢Δ

    View Slide

  140. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    `enum`.case(casePath)
    "
    Binding
    case(casePath) ͸ Case Paths Λར༻ͨ͠ function
    Binding ͔Β Binding Λநग़͢Δ

    View Slide

  141. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    `enum`.case(casePath)
    "
    Binding
    `enum`.case(casePath)
    .isPresented()
    "
    Binding
    case(casePath) ͸ Case Paths Λར༻ͨ͠ function
    Binding ͔Β Binding Λநग़͢Δ

    View Slide

  142. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    ???
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  143. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    Binding(
    unwrapping: `enum`.case(casePath)
    ).map(content)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  144. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    Binding(
    unwrapping: `enum`.case(casePath)
    ).map(content)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    `enum`.case(casePath)
    "
    Binding

    View Slide

  145. enum Ͱ΋ѻ͍΍͍͢ sheet API Λߟ͑Δ
    extension View {
    func sheet(
    unwrapping enum: Binding,
    case casePath: CasePath,
    @ViewBuilder content: @escaping (Binding) -> Content
    ) -> some View where Content: View {
    self.sheet(
    isPresented: `enum`.case(casePath).isPresented()
    ) {
    Binding(
    unwrapping: `enum`.case(casePath)
    ).map(content)
    }
    }
    }
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads
    `enum`.case(casePath)
    "
    Binding
    Binding(unwrapping:)
    "
    Binding
    "
    map

    View Slide

  146. Before / After
    struct ContentView: View {
    enum Route {
    // ...
    }
    @State var route: Route?
    var body: some View {
    BaseView(...)
    .sheet(
    unwrapping: $route,
    case: /Route.draft
    ) { $draft in
    EditPostView(post: $draft)
    }
    // ...
    }
    }
    struct ContentView: View {
    @State var draft: Post?
    @State var settings: Settings?
    @State var userProfile: Profile?
    var body: some View {
    BaseView(...)
    .sheet(item: self.$draft) { draft in
    EditPostView(post: draft)
    }
    .sheet(item: self.$settings) { settings in
    SettingsView(settings: settings)
    }
    .sheet(item: self.$userProfile) { userProfile in
    UserProfile(profile: userProfile)
    }
    }
    }
    #FGPSF "GUFS
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔ > ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ > Navigation Λ enum Ͱ؅ཧͰ͖ΔΑ͏ʹ͢Δ API overloads

    View Slide

  147. Navigation API ͷվળʹΑΔޮՌ
    • SwiftUI ͷ Navigation API ʹ͓͚Δ ՝୊Λ API overloads ͱ͍͏

    γϯϓϧͳํ๏ͰղܾͰ͖ͨ (ϥΠϒϥϦͷ࣮૷͸΋ͬͱચ࿅͞Ε͍ͯ·͢)


    1. ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    2. ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    3. ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • Navigation API ͕ΑΓ҆શͰѻ͍΍͘͢ͳΓɺNavigation ʹؔΘΔঢ়ଶͷ؅ཧ΋
    ༰қʹͳΔ
    Navigation API ͷ՝୊ʹͲ͏ཱͪ޲͔͏͔

    View Slide

  148. ·ͱΊ

    View Slide

  149. ·ͱΊ
    • SwiftUI ʹ͸༷ʑͳ Navigation API ͕͋ΓɺOS ͱڞʹܹ͍͠มԽ͕
    ͋ͬͨ


    • େ͖͘ Navigation API ͸ҎԼͷ 2 छྨʹ۠ผͰ͖Δ


    • Fire and forget API


    • State driven API

    View Slide

  150. ·ͱΊ
    • SwiftUI ͷ Navigation API ʹ͸ҎԼͷΑ͏ͳ՝୊͕͋ΓɺAPI Λద੾ʹ overload ͯ͠ղܾ͢Δ

    ʮswiftui-navigationʯͷΑ͏ͳΞϓϩʔν΋ଘࡏ͍ͯ͠Δ


    • ભҠઌͷը໘ʹ Binding value Λ౉͢ػߏΛඋ͍͑ͯͳ͍


    • ঢ়ଶ؅ཧΛෳࡶʹͤ͞Δ API ͕ଘࡏ͍ͯ͠Δ


    • ෳ਺ͷ Navigation Λ؅ཧͩ͢͠ͱແବͳঢ়ଶ͕૿͑Δ


    • SwiftUI ͷ Navigation Λਖ਼͘͠ཧղͯ͠؅ཧ͢Ε͹৭ʑͳԸܙ͕͋Δ


    • Navigation ʹؔΘΔঢ়ଶ؅ཧʹ೰·͞Εͳ͍


    • Deep Link ͕༰қʹͳΔɾXcode Previews ΋׆༻͠΍͘͢ͳΔ

    View Slide

  151. ࢀߟ
    • https://www.pointfree.co/collections/swiftui/navigation


    • https://gist.github.com/mbrandonw/f8b94957031160336cac6898a919cbb7


    • https://github.com/pointfreeco/swift-composable-architecture/discussions/1140


    • https://developer.apple.com/documentation/swiftui


    • https://github.com/pointfreeco/swiftui-navigation


    • https://swiftwithmajid.com/2022/06/15/mastering-navigationstack-in-swiftui-navigator-
    pattern/


    • https://swiftwithmajid.com/2022/06/21/mastering-navigationstack-in-swiftui-deep-
    linking/

    View Slide

  152. After Party iOSDC ͥͻ͝ࢀՃ͍ͩ͘͞ʂ

    View Slide