जब एक `नेविगेशन व्यू` में` नैविगेशन`टाइम्स `के अंदर` नेविगेशनलिंक` रखने के बाद पीछे की ओर नेविगेट करने पर मेरा स्विफ्टयूआई ऐप क्रैश क्यों होता है?


47

न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण (Xcode 11.2 बीटा, यह Xcode 11.1 में काम करता है):

struct Parent: View {
    var body: some View {
        NavigationView {
            Text("Hello World")
                .navigationBarItems(
                    trailing: NavigationLink(destination: Child(), label: { Text("Next") })
                )
        }
    }
}

struct Child: View {
    @Environment(\.presentationMode) var presentation
    var body: some View {
        Text("Hello, World!")
            .navigationBarItems(
                leading: Button(
                    action: {
                        self.presentation.wrappedValue.dismiss()
                    },
                    label: { Text("Back") }
                )
            )
    }
}

struct ContentView: View {
    var body: some View {
        Parent()
    }
}

समस्या एक स्विफ्टयूआई दृश्य के अंदर नेस्टेड NavigationLinkएक navigationBarItemsसंशोधक के अंदर रखने में झूठ लगती है जिसका मूल दृश्य ए है NavigationView। क्रैश रिपोर्ट इंगित करती है कि मैं एक व्यू कंट्रोलर को पॉप करने की कोशिश कर रहा हूं जो तब मौजूद नहीं होता जब मैं आगे Childऔर फिर वापस नेविगेट करता हूं Parent

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'
*** First throw call stack:

अगर मैं इसके बजाय NavigationLinkनीचे की तरह देखने के शरीर में जगह है , यह ठीक काम करता है।

struct Parent: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: Child(), label: { Text("Next") })
        }
    }
}

क्या यह एक स्विफ्टयूई बग या अपेक्षित व्यवहार है?

संपादित करें: मैंने Apple के साथ उनके फीडबैक सहायक में ID के साथ एक समस्या खोली है, जब कोई FB7423964Apple से वजन कम करने की कोशिश करता है।

संपादित करें: प्रतिक्रिया सहायक में मेरा खुला टिकट इंगित करता है कि 10 + समान रिपोर्ट किए गए मुद्दे हैं। उन्होंने संकल्प के साथ अद्यतन किया है Resolution: Potential fix identified - For a future OS update। फिंगर्स ने तय किया कि जल्द ही फिक्स भूमि।

संपादित करें: यह iOS 13.3 में तय किया गया है!


ऊपर दिया गया उदाहरण Xcode 11.2 बीटा के साथ ठीक काम करता है। क्या हम यहाँ कुछ याद कर रहे हैं?
सुब्रमण्यम मारियाप्पन

@SubramanianMariappan यह मेरे लिए 11.2 बीटा पर ठीक काम कर रहा है।
फरहान अमजद

1
दिलचस्प है, यह हर बार मेरे लिए दुर्घटनाग्रस्त हो जाता है। मैंने एक नई परियोजना बनाने और उस सटीक कोड को कॉपी करने की भी कोशिश की ContentView.swift। मैं पोस्ट को संपादित करूँगा, लेकिन क्रैश केवल तब होता है जब आप आगे और फिर वापस नेविगेट करते हैं।
रॉबर्ट

बड़ा अच्छा सवाल! यहां आपका उदाहरण हर बार मेरे लिए भी दुर्घटनाग्रस्त होता है। मैंने बस एक नया उत्तर पोस्ट किया है जो मेरे लिए बहुत अच्छा काम करता है। मुझे बताएं कि क्या यह आपके लिए भी काम करता है। धन्यवाद।
चक एच

1
सेब टिकट के बारे में अद्यतन के लिए धन्यवाद!
8

जवाबों:


20

यह मेरे लिए काफी दर्द की बात थी! मैंने इसे तब तक छोड़ दिया जब तक कि मेरा अधिकांश ऐप पूरा नहीं हो गया और मेरे पास दुर्घटनाग्रस्त होने से निपटने के लिए दिमाग की जगह थी।

मुझे लगता है कि हम सभी सहमत हो सकते हैं कि SwifUI के साथ कुछ बहुत बढ़िया सामान हैं लेकिन यह डीबगिंग मुश्किल हो सकता है।

मेरी राय में, मैं कहूंगा कि यह एक BUG है। यहाँ मेरा तर्क है:

  • यदि आप प्रेजेंटेशन लपेटते हैं तो लगभग डेढ़ सेकंड की अतुल्यकालिक देरी में कॉल को खारिज कर देते हैं, आपको यह पता लगाना चाहिए कि प्रोग्राम अब क्रैश नहीं होगा।

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        self.presentationMode.wrappedValue.dismiss()
    } 
  • इससे मुझे पता चलता है कि बग गहराई से एक अप्रत्याशित व्यवहार तरीका है जिसमें स्विफ्टयूआई विभिन्न विचारों को प्रबंधित करने के लिए अन्य सभी यूआईकिट कोड के साथ हस्तक्षेप करता है। आपके वास्तविक कोड के आधार पर, आप पा सकते हैं कि यदि दृश्य में कुछ मामूली जटिलता है, तो दुर्घटना वास्तव में नहीं होगी। उदाहरण के लिए, यदि आप किसी ऐसे दृश्य से खारिज कर रहे हैं जिसमें एक सूची है, और वह सूची खाली है, तो आपको एसिंक्रोनस विलंब के बिना क्रैश मिलेगा। दूसरी ओर, यदि आपके पास उस सूची दृश्य में केवल एक प्रविष्टि है, तो पैरेंट दृश्य उत्पन्न करने के लिए एक लूप पुनरावृत्ति को मजबूर करते हुए, आप देखेंगे कि दुर्घटना नहीं होगी।

मुझे इतना यकीन नहीं है कि देरी में कॉल खारिज करने का मेरा समाधान कितना मजबूत है। मुझे इसका और परीक्षण करना है। यदि आपके पास इस पर विचार हैं, तो कृपया मुझे बताएं! मुझे आपसे सीखकर बहुत खुशी होगी!


1
बहुत चालाक! मैंने ऐसा नहीं सोचा था। उम्मीद है कि यह जल्द ही तय हो जाएगा!
रॉबर्ट

1
@ रॉबर्ट ने क्या यह आपकी समस्या को ठीक किया? एक असंबंधित मुद्दे के बाद से यह एक कठिन है जो मैंने पाया है कि बाल नेविगेशन दृश्यों के अंदर एक पिकर का उपयोग कर रहा है। एक खंडित बीनने वाला स्टाइल काम करता है, वहीं बैक बटन पर क्लिक करने पर डिफ़ॉल्ट उसी बिंदु पर क्रैश का कारण बनता है। हम आगे चर्चा कर सकते हैं अगर यह अभी भी आपको दु: ख दे रहा है। पुनश्च। मुझे अपने समाधान से नफरत है। यह एक हैक है, लेकिन यह एक है जिसे कोड अपडेट की आवश्यकता नहीं होनी चाहिए अगर Apple समय समस्या को ठीक करता है।
जस्टिन

2
मैं मानता हूं कि समय का पहलू, इस तथ्य के साथ कि यह ११.१ में ठीक काम करता है और .navigationBarItems()अंक से बाहर काम करता है ।
जॉन एम।

3
हां, मेरा मानना ​​है कि यह एक बग है और यह इनाम पुरस्कार के लिए मेरा वर्तमान अग्रणी उम्मीदवार है। चूँकि मेरे पास इस लेखन के समय के रूप में इनाम पर 4 दिन शेष हैं, इसलिए मैं किसी भी मामले में नई जानकारी के साथ आने की स्थिति में हूँ।
रॉबर्ट

1
यह एक बहुत ही रोचक टिप था, इसके लिए धन्यवाद! दुर्भाग्य से मैं अभी भी मज़बूती से ऐप को 100% सिम्युलेटर में क्रैश कर रहा हूं: / यह डिवाइस पर बेहतर काम करता है, लेकिन दुर्घटनाग्रस्त हुए बिना नहीं है। लेकिन वो भी बिना देर किए।
किलन

15

इससे मुझे भी काफी समय से निराशा हुई है। पिछले कुछ महीनों में, Xcode संस्करण, सिम्युलेटर संस्करण और वास्तविक डिवाइस प्रकार और / या संस्करण के आधार पर, यह फिर से काम करने में असफल होने से चला गया है, प्रतीत होता है कि यादृच्छिक रूप से। हालाँकि, हाल ही में यह मेरे लिए लगातार असफल रहा है, इसलिए कल मैंने इसमें एक गहरा गोता लगाया। मैं वर्तमान में Xcode संस्करण 11.2.1 (11B500) का उपयोग कर रहा हूं।

ऐसा लगता है कि यह मुद्दा नव बार के चारों ओर घूमता है और जिस तरह से इसमें बटन जोड़े गए थे। इसलिए बटन के लिए एक नेविगेशनलिंक () का उपयोग करने के बजाय, मैंने एक मानक बटन () का उपयोग करने की कोशिश की, जिसमें एक @State संस्करण सेट किया गया है जो एक छिपे हुए नेविगेशनलिंक को सक्रिय करता है। यहाँ रॉबर्ट के जनक दृश्य के लिए एक प्रतिस्थापन है:

struct Parent: View {
    @State private var showingChildView = false
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: Child(),
                               isActive: self.$showingChildView)
                { EmptyView() }
                    .frame(width: 0, height: 0)
                    .disabled(true)
                    .hidden()            
             }
             .navigationBarItems(
                 trailing: Button(action:{ self.showingChildView = true }) { Text("Next") }
             )
        }
    }
}

मेरे लिए, यह सभी सिमुलेटरों और सभी वास्तविक उपकरणों पर बहुत लगातार काम करता है।

यहाँ मेरे सहायक विचार हैं:

struct HiddenNavigationLink<Destination : View>: View {

    public var destination:  Destination
    public var isActive: Binding<Bool>

    var body: some View {

        NavigationLink(destination: self.destination, isActive: self.isActive)
        { EmptyView() }
            .frame(width: 0, height: 0)
            .disabled(true)
            .hidden()
    }
}

struct ActivateButton<Label> : View where Label : View {

    public var activates: Binding<Bool>
    public var label: Label

    public init(activates: Binding<Bool>, @ViewBuilder label: () -> Label) {
        self.activates = activates
        self.label = label()
    }

    var body: some View {
        Button(action: { self.activates.wrappedValue = true }, label: { self.label } )
    }
}

यहाँ उपयोग का एक उदाहरण है:

struct ContentView: View {
    @State private var showingAddView: Bool = false
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, World!")
                HiddenNavigationLink(destination: AddView(), isActive: self.$showingAddView)
            }
            .navigationBarItems(trailing:
                HStack {
                    ActivateButton(activates: self.$showingAddView) { Image(uiImage: UIImage(systemName: "plus")!) }
                    EditButton()
            } )
        }
    }
}

मैं इस काम की पुष्टि कर सकता हूं (वास्तव में हैक के लिए अच्छी तरह से ;-))! Apple को हालांकि इस asap को ठीक करने की आवश्यकता है। Xcode 11.2.1, कैटालिना 10.15.2 (बीटा), iOS 13.2.2
पी। एनटी

1
मैं 100% सहमत हूं। सामान्य तौर पर, स्विफ्टयूआई में नेविगेशन के संबंध में, बहुत कुछ है जो या तो टूट गया है या बस सादा लापता है। कौन सा कोर्स हमें वास्तविक समस्या की ओर ले जाता है। Apple से कोई "सत्य का स्रोत" (यानी प्रलेखन और उदाहरण) नहीं है, केवल हमारी तरह हैक करता है। BTW, मैं उपरोक्त तकनीक का उपयोग करता हूं, मैंने दो उपयोगिता विचार बनाए हैं जो पठनीयता के साथ बहुत मदद करते हैं। अगर कोई दिलचस्पी रखता है तो मैं उन्हें अपने जवाब में जोड़ दूंगा।
चक एच

वर्कअराउंड के लिए धन्यवाद, यह सिर्फ काम करता है!
स्टैनिस्लाव पोस्क्लेव्स्की

1
यह मेरे लिए एक से अधिक नेविगेशन के लिए काम नहीं करता है। एक बार जब आप पिछली स्क्रीन पर वापस आ जाते हैं, तो अदृश्य लिंक अब काम नहीं करता है।
जॉन शियर

1
मेरे पास 13.3 पर कई वास्तविक उपकरण हैं (17C54 का निर्माण) और वे सभी वांछित के रूप में काम करते हैं। चूंकि मैं अपने सभी परीक्षण लगभग सभी वास्तविक उपकरणों पर करता हूं, इसलिए मैं बहुत बार सिम्युलेटर का उपयोग नहीं करता हूं। लेकिन मैंने सिर्फ 13.3 सिम्युलेटर पर अपने परीक्षण के मामले की कोशिश की और परीक्षण वहां विफल रहता है। मैंने ध्यान दिया कि Xcode सिम्युलेटर पर iOS 13.3 सार्वजनिक अपडेट की तुलना में एक पुराना बिल्ड (17C45) है। मुझे यह जानने में दिलचस्पी होगी कि क्या कोई वास्तविक डिवाइस पर विफल व्यवहार को देखता है।
चक एच

12

यह एक प्रमुख बग है और मैं इसके आसपास काम करने का उचित तरीका नहीं देख सकता। IOS 13 / 13.1 में ठीक काम किया, लेकिन 13.2 क्रैश।

आप वास्तव में इसे बहुत सरल तरीके से दोहरा सकते हैं (यह कोड वस्तुतः आप सभी की जरूरत है)।

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!").navigationBarTitle("To Do App")
                .navigationBarItems(leading: NavigationLink(destination: Text("Hi")) {
                    Text("Nav")
                    }
            )
        }
    }
}

आशा है कि Apple इसे सुलझा लेगा क्योंकि यह निश्चित रूप से SwiftUI ऐप (मेरा सहित) का भार तोड़ देगा।


हाहा ... यह बहुत बढ़िया है। आपने एक पाठ दृश्य में नेविगेट किया है, जो कि स्विफ्टयूआई में है, एक दृश्य है! हाँ, यह वापस आ जाना चाहिए कि यह माता-पिता को नहीं होना चाहिए? फिर भी, यह नहीं है। यह दिलचस्प है कि आपके उदाहरण से व्यवहार यूआई को तोड़ता है लेकिन वास्तव में एक घातक दुर्घटना का कारण नहीं बनता है।
जस्टिन

हाँ, SwiftUI (और प्रतिक्रिया मूल / स्पंदन आदि) की रचना अविश्वसनीय है। आपको इतना नियंत्रण / लचीलापन देता है (जब यह कम से कम काम करता है)।
जेम्स

1
कैटालिना (10.15.1), Xcode (11.2.1), iOS (13.2.2)
P. Ent

यह अब 13.3 में दुर्घटनाग्रस्त हो जाता है, हालांकि नेविगेशन केवल पहली बार काम करने के लिए लगता है जब आप इसे ट्रिगर करते हैं
जेम्स

6

ऊपर के चक एच के जवाब के आधार पर, वर्कअराउंड के रूप में, मैंने नेवीगेशनलिंक को एक छिपे हुए तत्व के रूप में समझाया है:

struct HiddenNavigationLink<Content: View>: View {
var destination: Content
@Binding var activateLink: Bool

var body: some View {
    NavigationLink(destination: destination, isActive: self.$activateLink) {
        EmptyView()
    }
    .frame(width: 0, height: 0)
    .disabled(true)
    .hidden()
}
}

फिर आप इसे एक नेविगेशन दृश्य (जो महत्वपूर्ण है) के भीतर उपयोग कर सकते हैं और इसे नेवी बार में एक बटन से ट्रिगर कर सकते हैं:

VStack {
    HiddenNavigationList(destination: SearchView(), activateLink: self.$searchActivated)
    ...
}
.navigationBarItems(trailing: 
    Button("Search") { self.searchActivated = true }
)

इसे "// HACK" टिप्पणियों में लपेटें ताकि जब Apple इसे ठीक कर दे तो आप इसे बदल सकते हैं।


यह केवल iOS 13.3 में पहले उपयोग पर काम करता है।
जेम्स

3

आपके द्वारा प्रदान की गई जानकारी और विशेष रूप से उस टिप्पणी के आधार पर, जो @Robert ने बनाई है, जहां के बारे में नेविगेशनवीच को रखा गया है, मुझे कम से कम मेरे विशिष्ट परिदृश्य पर समस्या को हल करने का एक तरीका मिल गया है।

मेरे मामले में मेरे पास एक TabView था जो इस तरह से एक नेविगेशन दृश्य में संलग्न था:

struct ContentViewThatCrashes: View {
@State private var selection = 0

var body: some View {
    NavigationView{
        TabView(selection: $selection){
            NavigationLink(destination: NewView()){
                Text("First View")
                    .font(.title)
            }
            .tabItem {
                VStack {
                    Image("first")
                    Text("First")
                }
            }
            .tag(0)
            NavigationLink(destination: NewView()){
                Text("Second View")
                    .font(.title)
            }
            .tabItem {
                VStack {
                    Image("second")
                    Text("Second")
                }
            }
            .tag(1)
        }
    }
  }
}

यह कोड क्रैश हो जाता है क्योंकि हर कोई iOS 13.2 में रिपोर्ट कर रहा है और iOS 13.1 में काम करता है। कुछ शोध के बाद मैंने इस स्थिति के लिए एक समाधान निकाला।

मूल रूप से, मैं इस तरह से प्रत्येक टैब पर अलग से प्रत्येक स्क्रीन पर नेविगेशन दृश्य को स्थानांतरित कर रहा हूं:

struct ContentViewThatWorks: View {
@State private var selection = 0

var body: some View {
    TabView(selection: $selection){
        NavigationView{
            NavigationLink(destination: NewView()){
                Text("First View")
                    .font(.title)
            }
        }
        .tabItem {
            VStack {
                Image("first")
                Text("First")
            }
        }
        .tag(0)
        NavigationView{
            NavigationLink(destination: NewView()){
                Text("Second View")
                    .font(.title)
            }
        }
        .tabItem {
            VStack {
                Image("second")
                Text("Second")
            }
        }
        .tag(1)
    }
  }
}

किसी तरह सादगी के SwiftUI के खिलाफ जाता है, लेकिन यह iOS 13.2 पर काम करता है।


यह काम करता है लेकिन, समस्या NewView पर tabViews को हटा रही है।
FRIDDAY

1
@FRIDD यह उदाहरण 13.1 में काम करता है लेकिन 13.2 में क्रैश हो जाता है। यह एक ज्ञात बग है और मेरा इरादा एक ही परिदृश्य में किसी व्यक्ति को एक वर्कअराउंड के साथ मदद करने की कोशिश करना था
Julio Bailon

1

Xcode 11.2.1 स्विफ्ट 5

समझ गया! यह मुझे पता करने के लिए एक दो दिन लग गए ...

मेरे मामले में जब SwiftUI का उपयोग कर रहा हूं तो केवल तभी दुर्घटना हो रही है जब मेरी सूची के निचले भाग को स्क्रीन से आगे बढ़ाया गया है और फिर मैं किसी भी सूची आइटम को "स्थानांतरित" करने का प्रयास करता हूं। मैंने जो निष्कर्ष निकाला वह यह है कि यदि मेरे पास सूची () के नीचे बहुत अधिक "सामान" है, तो यह कदम पर दुर्घटनाग्रस्त हो जाता है। उदाहरण के लिए, मेरी सूची के नीचे () मेरे पास एक पाठ (), स्पेसर (), बटन (), स्पेसर () बटन () है। अगर मैंने उन वस्तुओं में से किसी एक पर टिप्पणी की, तो अचानक मैं दुर्घटना को फिर से नहीं बना सका। मैं निश्चित नहीं हूं कि सीमाएं क्या हैं, लेकिन अगर आपको यह दुर्घटना हो रही है तो अपनी सूची के नीचे की वस्तुओं को हटाकर देखें कि क्या यह मदद करती है।


0

हालाँकि मैं कोई क्रैश नहीं देख सकता, लेकिन आपके कोड में कुछ समस्याएँ हैं:

अग्रणी आइटम सेट करके, आप वास्तव में नेविगेशन बदलावों के डिफ़ॉल्ट व्यवहार को मार देते हैं। (अगर यह काम करता है, तो यह देखने के लिए अग्रणी पक्ष से स्वाइप करें)।

तो वहाँ एक बटन की जरूरत नहीं है। बस इसे वैसे ही छोड़ दें और आपके पास एक मुफ्त बैक बटन है।

और एचआईजी के अनुसार मत भूलना , बैक बटन शीर्षक को दिखाना चाहिए कि यह कहां जाता है, कि यह क्या है! इसलिए पहले पृष्ठ के लिए एक शीर्षक सेट करने का प्रयास करें कि यह किसी भी बैक बटन को दिखाता है जो इसे पॉप करता है।

struct Parent: View {
    var body: some View {
        NavigationView {
            Text("Hello World")
                .navigationBarItems(
                    trailing: NavigationLink(destination: Child(), label: { Text("Next") })
                )
                .navigationBarTitle("First Page",displayMode: .inline)
        }
    }
}

struct Child: View {
    @Environment(\.presentationMode) var presentation
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView: View {
    var body: some View {
        Parent()
    }
}

1
अरे, उत्तर के लिए धन्यवाद। जबकि मैं मानता हूं कि डिफ़ॉल्ट बैक बटन व्यवहार को छोड़ना वांछनीय है, फिर भी यह एक दुर्घटना पैदा करता है।
रॉबर्ट

आप कौन सा संस्करण उपयोग कर रहे हैं? मैंने भेजने से पहले इसका परीक्षण किया है। शायद आपके पास एक और मुद्दा है। क्या आप कृपया एक नमूना परियोजना प्रदान कर सकते हैं?
मोजतबा होसेनी

1
Xcode 11.2 बीटा जैसा प्रश्न कहता है। प्रश्न में मैंने जो उदाहरण दिया है, वह आपको दुर्घटना को पुन: उत्पन्न करने की आवश्यकता है।
रॉबर्ट

मैं समान संस्करण और समान कोड का उपयोग कर रहा हूं, लेकिन कोई दुर्घटना नहीं हुई same
Mojtaba Hosseini

1
कैटालिना (10.15.1), Xcode (11.2.1), iOS (13.2.2)
P. Ent

0

एफडब्ल्यूआईडब्ल्यू - एक छिपे हुए नेविगेशनलिंक हैक का सुझाव देने के ऊपर दिए गए समाधान अभी भी iOS 13.3b3 में सबसे अच्छा समाधान है। मैंने भी पोस्टबेरिटी के लिए FB7386339 दायर किया है, और अन्य एफबीएस के समान ही बंद कर दिया गया है: "संभावित फिक्स की पहचान - भविष्य के ओएस अपडेट के लिए"।

उंगलियों को पार कर।


कृपया टिप्पणियों को उत्तर के रूप में जोड़ने से बचें।
कार्तिक रमेश

0

इसे iOS 13.3 में हल किया गया है। बस अपने OS और xCode को अपडेट करें।


1
10.15.2 को Xcode 11.3 (11C29) मेरे लिए एक अलग व्यवहार का परिणाम है: बैकवर्ड नेविगेशन काम कर रहा है, लेकिन बाद में नेविगेशनलिंक का अब कोई कार्य नहीं है। इसे क्लिक करने से कुछ नहीं होता है।
malte

@ नल इसके लिए एक नया प्रश्न खोलना बेहतर है। इससे पहले कि मैं आपके कोड की जांच करूँ, अपना नेवीगेशनलिंक .buttonStyle(PlainButtonStyle())मॉडिफ़ायर दें और इसे फिर से आज़माएँ। यदि आपने कोई प्रश्न पूछा है तो मुझे बताएं।
फ्रेडडे

1
आप सही हे। पता चला कि पहले से ही एक नया सवाल है: stackoverflow.com/questions/59279176/…
malte
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.