Post

Replies

Boosts

Views

Activity

Reply to When using keyboardShortcut, instance of StateObject is not deinitialized
Upon further investigation, I believe there's a high possibility that this is a bug. In the code below, model2 is not referenced by Button.action, yet deinit is not called for model2 just like for model. struct ContentView: View { @StateObject var model = Model() @StateObject var model2 = Model2() var body: some View { VStack { Button("Toggle") { model.flag.toggle() } .keyboardShortcut(.space, modifiers: []) } .padding() } } @MainActor class Model: ObservableObject{ @Published var flag: Bool = false init() { print("Model.init") } deinit { print("Model.deinit") } } @MainActor class Model2: ObservableObject{ @Published var flag: Bool = false init() { print("Model2.init") } deinit { print("Model2.deinit") } }
Oct ’23
Reply to Infinite Loop Issue with View's onAppear and onDisappear in iOS 17 Beta
In my app, the above workaround caused another problem. But, I could avoid it by changing the next code using DispatchQueue.main.async. I hope this issue will be resolved by the public release of iOS 17. struct SampleSection: View { @State private var isLoaded = false var body: some View { let _ = Self._printChanges() Group { if !isLoaded { Section("Header") {} .hidden() } else { Section("Header") { Text("Text") } } } .onAppear { DispatchQueue.main.async { // or Task { @MainActor in NSLog("SampleSection onAppear.") isLoaded = true } } .onDisappear() { DispatchQueue.main.async { // or Task { @MainActor in NSLog("Sample Section onDisappear.") isLoaded = false } } } }
Jul ’23
Reply to Infinite Loop Issue with View's onAppear and onDisappear in iOS 17 Beta
Here is a workaround for this issue in the reproduction code. struct SampleSection: View { @State private var isLoaded = false var body: some View { let _ = Self._printChanges() if !isLoaded { Section("Header") {} .hidden() .onAppear { NSLog("SampleSection onAppear.") isLoaded = true } } else { Section("Header") { Text("Text") } .onDisappear() { NSLog("Sample Section onDisappear.") isLoaded = false } } } }
Jul ’23
Reply to iOS 16.4 NavigationStack Behavior Unstable
After modifying the ContentView as shown below, the transition to the SubView now works. (🌟 indicates the modified parts) However, since the cause of the issue is unknown, I cannot judge whether this is an appropriate workaround or not. struct ContentView: View { @StateObject private var model = ContentModel() @State private var selectedData: Value? // 🌟 @State private var isShowingSubView = false @Environment(\.dismiss) private var dismiss init() { } var body: some View { List(selection: $selectedData) { ForEach(model.vals) { val in NavigationLink(value: val) { Text("\(val.num)") } } } // 🌟 .onChange(of: selectedData, perform: { newValue in // In production code, convert data here. isShowingSubView = newValue != nil }) .navigationDestination(isPresented: $isShowingSubView, destination: { SubView(kind: model.kind) // SubView() }) .onChange(of: isShowingSubView) { newValue in if !newValue && selectedData != nil { selectedData = nil } } } }
Apr ’23
Reply to iOS 16.4 NavigationStack Behavior Unstable
I have created a reproduction code. However, this issue cannot be reproduced with just this code. In my case, it occurs only in the iOS 16.4 environment when Google AdMob is installed via CocoaPods. In this case, the 🌟 SubView gets caught in an infinite loop regardless of which SubView is called. If you comment out the 🌟🌟 "@Environment(.dismiss) private var dismiss" line, it seems to work properly. Additionally, this code worked correctly on the iOS 16.0 and iOS 16.2 simulators. I am not sure if the cause of this problem lies in SwiftUI iOS 16.4 or Google AdMob (or if it's a significant misunderstanding on my part), but I hope for a prompt resolution. Here is the environment I tested in: Xcode Version 14.3 (14E222b) CocoaPods: 1.11.3, 1.12.0 AdMob: 9.14.0, 10.3.0 import SwiftUI @main struct iOS16_4NavigationSample2App: App { var body: some Scene { WindowGroup { NavigationStack { NavigationLink { ContentView() } label: { Text("Content") } } } } } enum Kind { case none, a, b, c } struct Value: Hashable, Identifiable { let id: UUID = UUID() var num: Int } @MainActor class ContentModel: ObservableObject { @Published var kind: Kind = .a @Published var vals: [Value] = { return (1...5).map { Value(num: $0) } }() } struct ContentView: View { @StateObject private var model = ContentModel() @State private var selectedData: Value? // 🌟🌟 @Environment(\.dismiss) private var dismiss init() { } var body: some View { List(selection: $selectedData) { ForEach(model.vals) { val in NavigationLink(value: val) { Text("1") } } } .navigationDestination(isPresented: .init(get: { selectedData != nil }, set: { val in if !val { selectedData = nil } }), destination: { // 🌟 SubView(kind: model.kind) // SubView() }) } } struct SubView: View { init(kind: Kind) { print("init(kind:)") } init() { print("init") } var body: some View { Text("Content") } } # Podfile source 'https://github.com/CocoaPods/Specs.git' platform :ios, '16.0' target 'iOS16_4NavigationSample2' do use_frameworks! pod 'Google-Mobile-Ads-SDK' end
Mar ’23
Reply to iOS 16.4 NavigationStack Behavior Unstable
@nteissler Your comment helped me to calm down. I have encountered bugs in NavigationView and NavigationStack, such as those described in the following links, multiple times, which has made it difficult for me to remain calm. https://developers.apple.com/forums/thread/715589 https://developers.apple.com/forums/thread/715970 https://developers.apple.com/forums/thread/693137 I am currently trimming down the production code and preparing the reproduction code. I have figured out the situations when the issue occurs and when it doesn't in the production code, but I have not yet reached the point of having a reproduction code. In the production code, an infinite loop occurs on iOS 16.4 when referencing a StateObject in navigationDestination. Without referencing the StateObject, the infinite loop does not occur. I have attached the reproducible code that I am currently working on below, with the relevant part marked with a 🌟. Of course, there is a possibility that there is a bug in my code. However, I cannot understand why an infinite loop occurs depending on whether or not a StateObject is referenced. Furthermore, since the issue cannot be reproduced in the reproducible code, it may not be the root cause of the bug. I am still working on creating the reproducible code, and I will share the details as soon as I know more. enum Kind { case none, a, b, c } @MainActor class ContentModel: ObservableObject { @Published var kind: Kind = .a @Published var vals: [Selection] = { return (1...5).map { Selection(num: $0) } }() } // Selection is storing the selected values in the NavigationStack. struct Selection: Hashable, Identifiable { let id = UUID() let num: Int } // Data is corresponding to the selection. struct Data { let data: Int } struct ContentView: View { @StateObject var model: ContentModel = .init() @State var selection: Selection? @State var data: Data? var body: some View { list // Convert selection into data. .onChange(of: selection) { newValue in if let selection { data = Data(data: selection.num * 10) } else { data = nil } } } private var list: some View { List(selection: $selection) { ForEach(model.vals) { val in NavigationLink(value: val) { Text("\(String(describing: val))") } } } // In production code, this navigationDestination is defined as a Custom ViewModifier. .navigationDestination(isPresented: .init(get: { return data != nil }, set: { newValue in if !newValue { data = nil } }), destination: { // 🌟 If the StateObject is referenced here, the destination will end up in an infinite loop. // (This code has not yet reached the point of reproducing the issue, so it wont cause an infinite loop yet.) SubView(kind: model.kind) // If the StateObject is not referenced, it will transition to the SubView normally. // SubView() }) .onChange(of: selection) { newValue in if newValue == nil && data != nil { data = nil } } } } // struct SubView: View { init(kind: Kind) { } init() { } var body: some View { Text("Content") } }
Mar ’23
Reply to NavigationLink in NavigationStack doesn't work on iOS 16.0 and iOS 16.1 beta
I created a ViewModifier to work around this problem. If you are not using NavigationPath, NavigationDestinationSelectedViewModifier may be available. https://github.com/hmuronaka/NavigationDestinationSelectedViewModifier Example struct ContentView: View {     var body: some View {         NavigationLink("SubView") {             SubView()         }     } } struct SubView: View {     @State private var selection: Int?     var body: some View {         List(selection: $selection) {             ForEach(0...10, id: \.self) { idx in                 NavigationLink(value: idx) {                     Text("Detail \(idx)")                 }             }         }         .navigationDestination(selected: $selection, destination: { value in             DetailView(value: value)         })     } } struct DetailView: View {     let value: Int     var body: some View {         Text("\(value)")             .navigationTitle("Detail")     } }
Jan ’23
Reply to onAppear on a List row not always called in iOS 16
Hi, I found other problem with NavigationLink.disabled(_ :Bool) not working on iOS16. I put NavigationLink into HStack to try it out and disabled worked.(But I cannot explain why this works.) It seems that onAppear is always called in the following code. I hope this is helpful. struct ContentView: View {     @State var onAppeared: Set<Int> = .init()     var body: some View {         List() {             ForEach(0...100, id: \.self) { num in                 HStack {                     NavigationLink {                         Text("\(num)")                     } label: {                         Cell(num: num)                             .onAppear() {                                 NSLog("onAppear: \(num), count: \(onAppeared.count)")                                 onAppeared.insert(num)                             }                     }                 }             }         }     } } struct Cell: View {     let num: Int     var body: some View {         Text("label: \(num)")     } }
Oct ’22