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

AppStorage + Toggle in Settings will cause a UI render issue #117

Open
Kyle-Ye opened this issue Nov 1, 2023 · 2 comments
Open

AppStorage + Toggle in Settings will cause a UI render issue #117

Kyle-Ye opened this issue Nov 1, 2023 · 2 comments

Comments

@Kyle-Ye
Copy link
Contributor

Kyle-Ye commented Nov 1, 2023

import SwiftUI
struct ContentView: View {
    @AppStorage("Test") private var toggle = false
    @State private var toggle2 = false
    var body: some View {
        VStack {
            Toggle("Demo Toggle", isOn: $toggle)
            Toggle("Demo Toggle2", isOn: $toggle2)
            .padding()
        }
    }
}

Normally both toggle will work fine. But if we write such code under Settings.Section and build it with macOS 14 SDK(Xcode 15.0)

import SwiftUI
import Settings

struct ContentView: View {
    @AppStorage("Test")
    private var toggle = false

    @State
    private var toggle2 = false

    var body: some View {
        Settings.Container(contentWidth: 600) {
            Settings.Section {
                Text("Hello")
            } content: {
                Section {
                    Toggle("Demo Toggle", isOn: $toggle)
                    Toggle("Demo Toggle2", isOn: $toggle2)
                    .padding()
                }
            }
        }
    }
}

The toggle2 will work while toggle will not. The value stored in UserDefaults is actually changed in both case, but the UI is not updating in the first case automatically unless we trigger an update for toggle2.

See screen recording below if my description is vague

2023-11-01.14.04.28.mov
  • The issue only happens with Xcode 15/macOS 14 SDK + Preferences 2.6.0 in SwiftUI
  • It works fine with Xcode 14.3 + Preferences 2.5.0
@Kyle-Ye
Copy link
Contributor Author

Kyle-Ye commented Nov 6, 2023

Suspect this is a bug introduced by SwiftUI with AnyView usage in Settings.

Current workaround: (Move @AppStorage code into @Observable and manually write getter and setter)

import SwiftUI
import Settings

struct ContentView: View {
    @State private var s = S()
    var body: some View {
        Settings.Container(contentWidth: 600) {
            Settings.Section {
                Text("Hello")
            } content: {
                Section {
                    Toggle("Demo Toggle", isOn: $s.toggle)
                    Toggle("Demo Toggle2", isOn: $s.toggle2)
                    .padding()
                }
            }
        }
    }
}

@Observable
class S {
    var toggle: Bool {
        get {
            access(keyPath: \.toggle)
            return UserDefaults.standard.bool(forKey: "Test")
        }
        set {
            withMutation(keyPath: \.toggle) {
                UserDefaults.standard.setValue(newValue, forKey: "Test")
            }
        }
    }
    var toggle2 = false
}

@Kyle-Ye
Copy link
Contributor Author

Kyle-Ye commented Nov 6, 2023

FThe mini reproductive ContentView(Platform independent) code.

This is definitely a bug behavior on iOS 17 and macOS 14. But the bug's behavior is a little different

ContentView.swift.zip
(4 toggles: C1T1 C1T2 C2T1 C2T2 - C1T1&C2T1 use the same truth, C1T2&C2T2 use the same truth )

@AppStorage("Test") private var toggle = false
@State private var toggle2 = false

Container {
    Section {
        Toggle("Demo Toggle", isOn: $toggle)
        Toggle("Demo Toggle2", isOn: $toggle2)
    }
}
Container2(sections: [
    Section {
        Toggle("Demo Toggle", isOn: $toggle)
        Toggle("Demo Toggle2", isOn: $toggle2)
    }
])

macOS 14:

  • C1T1's UI will only be updated at most 1 time if we only tap T1. C2T1 will always reflect the latest value in UI. A tap for T2 will make C1T1's UI up to data.
  • Tap on C1T2 or C2T2 will update both toggle at the same time. (Expected)

iOS 17

  • Tap on C2T1 will only update toggle C2T1 while the UI of C1T1 remains the same.
  • Tap on C1T1 will update both toggle(C1T1 & C2T1) at the same time. (Expected)
  • Tap on C1T2 or C2T2 will update both toggle at the same time. (Expected)

Filed to Apple via FB13341321

@Kyle-Ye Kyle-Ye changed the title AppStorage + Toggle in Settings wil cause a UI render issue AppStorage + Toggle in Settings will cause a UI render issue Nov 6, 2023
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

1 participant