#swift #macos #swiftui
Вопрос:
Я использую бета-версию 4 macOS Montery вместе с бета-версией 4 Xcode 13, и я думаю, что обнаружил ошибку SwiftUI
.
При использовании CommandGroup
кнопки вместе с кнопкой, которая включена/отключена в зависимости от условия, CommandGroup
она не обновляется. CommandMenu
делает, однако.
Воспроизведение:
- Создайте новый проект SwiftUI для macOS
- Вставьте следующий код в
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)
}
}
}
}
- Вставьте следующий код в
ContentView
файл:
struct ContentView: View {
@EnvironmentObject var test: Test
var body: some View {
Button(action: {
test.num = 1
}) {
Text(String(test.num) " ---------")
}
}
}
- Запустите приложение и нажмите на
File
меню. Вы должны увидеть, что «Пункт меню» Тест » отключен, как и ожидалось. - Нажмите на кнопку. Это просто увеличивает число на 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. Спасибо за ответ! Я очень надеюсь, что это скоро исправят