Меню не обновляется (ошибка SwiftUI?)

#swift #macos #swiftui

Вопрос:

Я использую бета-версию 4 macOS Montery вместе с бета-версией 4 Xcode 13, и я думаю, что обнаружил ошибку SwiftUI .

При использовании CommandGroup кнопки вместе с кнопкой, которая включена/отключена в зависимости от условия, CommandGroup она не обновляется. CommandMenu делает, однако.

Воспроизведение:

  1. Создайте новый проект SwiftUI для macOS
  2. Вставьте следующий код в App файл:
 class Test: ObservableObject {
    @Published var num = 0
}

@main
struct TestApp: App {
    @StateObject private var test = Test()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(test)
        }
        .commands {
            CommandGroup(after: .newItem) {
                Button(action: {}) {
                    Text("Test menu item")
                }
                .disabled(test.num == 0)
            }
        }
    }
}
 
  1. Вставьте следующий код в ContentView файл:
 struct ContentView: View {
    @EnvironmentObject var test: Test
    
    var body: some View {
        Button(action: {
            test.num  = 1
        }) {
            Text(String(test.num)   " ---------")
        }
    }
}
 
  1. Запустите приложение и нажмите на File меню. Вы должны увидеть, что «Пункт меню» Тест » отключен, как и ожидалось.
  2. Нажмите на кнопку. Это просто увеличивает число на 1. Однако «Пункт меню» Тест » по-прежнему отключен, хотя test.num != 0.

Дело в том, что замена CommandGroup на CommandMenu("Test menu") исправляет это.

Все, что делает приложение, — это имеет пункт меню, который отключается, если число равно нулю. Нажатие кнопки делает это число не равным нулю, но пункт меню остается отключенным.

Кто-нибудь может воспроизвести это, и это ошибка с моей стороны?

Комментарии:

1. С помощью аналогичного примера приложения у меня возникла эта проблема в Big Sur, однако я не вижу этой проблемы на другой машине, на которой запущена последняя бета-версия Monterey. Однако для поддержки старых ОС мне, вероятно, придется использовать обходные пути здесь.

Ответ №1:

незначительная вариация ответа @George_E, это:

  CommandGroup(after: .newItem) {
       TestView(test: test)
 }
 
 struct TestView: View {
     @ObservedObject var test: Test
  
     var body: some View {
         Button(action: {}) {
             Text("Test menu item")
         }
         .disabled(test.num == 0)
     }
 }
 

Комментарии:

1. Похоже, ты можешь сделать это лучше, молодец! Я видел test.num , что обновления не производятся, поэтому я попробовал этот onReceive(_:perform:) подход, но, может test быть, обновлялся, чтобы это работало? Странная ошибка

Ответ №2:

Я бы не ожидал, что это будет преднамеренное поведение. Тем не менее, я нашел обходной путь, чтобы исправить это.

Странно, что onChange(of:perform:) он не запускается при test.num изменениях, но мы все еще можем обнаружить издателя. Поэтому я разделил это на отдельное представление, и когда представление получает новое значение, кнопка обновляется.

Код:

 CommandGroup(after: .newItem) {
    TestView(pub: test.$num)
}
 
 struct TestView: View {
    let pub: Published<Int>.Publisher
    @State private var disabled = true

    var body: some View {
        Button(action: {}) {
            Text("Test menu item")
        }
        .disabled(disabled)
        .onReceive(pub) { new in
            disabled = new == 0
        }
    }
}
 

Комментарии:

1. Спасибо за ответ! Я очень надеюсь, что это скоро исправят