Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xcode console always report a warning #2

Open
yikibug opened this issue Nov 28, 2024 · 3 comments
Open

Xcode console always report a warning #2

yikibug opened this issue Nov 28, 2024 · 3 comments

Comments

@yikibug
Copy link

yikibug commented Nov 28, 2024

Do not put a navigation destination modifier inside a "lazy” container, like List or LazyVStack. These containers create child views only when needed to render on screen. Add the navigation destination modifier outside these containers so that the navigation stack can always see the destination. There's a misplaced navigationDestination(isPresented:destination:) modifier presenting Optional<xxxx>. It will be ignored in a future release.

@sofbix
Copy link
Collaborator

sofbix commented Dec 4, 2024

So, yes.
I forgot to add in the component description how to use the modifier .navigation(..), and I corrected it:

  • Note that .navigation(..) applies to all content in the view being navigated from. This modifier should not be allowed to apply to child elements of that view, such as childs of ListView, LazyView and each others. Better use .navigation(..) below of all content of that view as in the code below.

Also have to added example for illustration mistakes using .navigation(..).
Incorrect that:

/// Incorrect implementation of the list when navigation is focused on each list item
struct FalseListView: View {

    var array = ListView.elements

    @State
    var isDetailsShow = false

    var body: some View {
        List(array, id: \.self) { item in
            Button {
                isDetailsShow = true
            } label: {
                Text(item)
                    .navigation(isActive: $isDetailsShow) {
                        DetailsView(text: item)
                    }
            }
        }
        .padding(0)
        .navigationTitle("Elements")
    }
}

Correct that:

/// Сorrect implementation of the list when navigation is focused on the entire screen and not on its individual elements
struct TrueListView: View {

    var array = ListView.elements

    @State
    var detailsItem: String? = nil

    var body: some View {
        List(array, id: \.self) { item in
            Button {
                detailsItem = item
            } label: {
                Text(item)
            }
        }
        .padding(0)
        .navigationTitle("Elements")
        .navigation(item: $detailsItem) { item in
            DetailsView(text: item)
        }
    }
}

For more information you can get example.
Does what I wrote cover this task? Can it be closed or do you have a different case?

@yikibug
Copy link
Author

yikibug commented Dec 9, 2024

In your example, If put ListView() in TabView, Xcode console still report a warning above.

import SwiftUI
import SUINavigation

@main
struct ListDetailsApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationViewStorage {
                TabView {
                    ListView()
                }
            }
        }
    }
}

And I found the warning relates to the following source code, delete by testing .modifier(modifier) no warning will be reported, but you can't actually delete it.

//
//  View.swift
//
//
//  Created by Sergey Balalaev on 26.01.2024.
//

import SwiftUI

public extension View {

    /// Facade target with optimisation
    /// for revert just edit to call self.modifier(modifier)
    @inlinable public func navigationModifier<T: ViewModifier>(_ modifier: T) -> some View
    {
        self.backgroundModifier(modifier)
    }

    /// Modifier with optimisation, but can down performance on first showing becase use EmptyView
    @inlinable func backgroundModifier<T: ViewModifier>(_ modifier: T) -> some View
    {
        self.background (
            EmptyView()
                 .modifier(modifier)
        )
    }
}

@sofbix
Copy link
Collaborator

sofbix commented Dec 9, 2024

Thanks for fully Answer.
I'am reseach about this problem. The root of them you have from NavigationStack + navigationDestination:

@main
struct ListDetailsApp: App {
    @State private var path: [String] = []

    var body: some Scene {
        WindowGroup {
            NavigationStack(path: $path) {
                TabView {
                    Tab("Received", systemImage: "tray.and.arrow.down.fill") {
                        EmptyView()
                            .navigationDestination(for: String.self) { route in
                                switch route {
                                case ".View1":
                                    Text("View1")
                                case ".View2":
                                    Text("View2")
                                default:
                                    Text("default")
                                }
                            }

                    }
                }
            }
        }
    }
}

It seems like TabView is also perceived as a "lazy” container, like List or LazyVStack. This bug is reproduced from iOS 18 here.
I promise to think about how to fix it.
Thanks a lot for this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants