使用 SwiftUI 的 Catalyst 应用程序中的键盘命令连续触发

Posted

技术标签:

【中文标题】使用 SwiftUI 的 Catalyst 应用程序中的键盘命令连续触发【英文标题】:Key command in Catalyst app using SwiftUI continuously fires 【发布时间】:2020-03-29 18:06:30 【问题描述】:

我正在使用 SwiftUI 构建一个 ios 应用程序,并希望也可以使用 Catalyst 在 Mac 上运行它。我在主主机控制器上使用UIKeyCommand 添加了键盘快捷键CMD+N,它会触发我的 ObservableObject 模型监听的Notification,切换警报属性以显示警报。代码如下:

class KeyCommandHostingController<Content: View>: UIHostingController<Content> 
    override var keyCommands: [UIKeyCommand]? 
        [
            UIKeyCommand(title: "New Game", action: #selector(postNewGame), input: "n", modifierFlags: .command)
        ]
    

    @objc func postNewGame() 
        print("postNewGame called")
        NotificationCenter.default.post(name: .newGameRequested, object: nil)
    



public extension Notification.Name 
   static let newGameRequested = Notification.Name(rawValue: "newGameRequested")


class Model: ObservableObject 
    @Published var presentAlert = false
    var cancellables = Set<AnyCancellable>()

    init() 
        NotificationCenter.default
            .publisher(for: .newGameRequested)
            .sink  [unowned self] _ in
                self.presentAlert.toggle()
                print("new game requested")
            
            .store(in: &cancellables)
    


struct ContentView: View 
    @ObservedObject var model: Model

    var body: some View 
        Text("Hello, World!")
            .alert(isPresented: $model.presentAlert) 
                Alert(title: Text("New Game"),
                      message: Text("Are you sure you want to start a new game? The current game will be recorded as a loss."),
                      primaryButton: Alert.Button.destructive(Text("New Game")) 
                        print("New Game selected")
                      ,
                      secondaryButton: Alert.Button.cancel()
                )
            
    

当我在 iPhone 或 iPad 模拟器中执行键盘命令时,它的行为正确 - 触发一个通知,并显示警报。但是,在 Mac Catalyst 应用程序中,按一次键盘快捷键会导致通知被无休止地触发,这会导致应用程序尝试一遍又一遍地无休止地显示警报。控制台输出证实了这一点,并带有以下无限输出(截断):

new game requested
postNewGame called
new game requested
postNewGame called
new game requested
postNewGame called
new game requested
2020-03-29 14:04:11.179475-0400 AlertMadness[1332:29452] Warning: Attempt to present <SwiftUI.PlatformAlertController: 0x10192de00> on <_TtGC12AlertMadness27KeyCommandHostingControllerVS_11ContentView_: 0x10310bcf0> while a presentation is in progress!
postNewGame called
new game requested
postNewGame called
new game requested
postNewGame called
new game requested
postNewGame called
new game requested
2020-03-29 14:04:11.595161-0400 AlertMadness[1332:29452] Warning: Attempt to present <SwiftUI.PlatformAlertController: 0x10195ca00> on <_TtGC12AlertMadness27KeyCommandHostingControllerVS_11ContentView_: 0x10310bcf0> while a presentation is in progress!
(etc...)

是我做错了什么,还是 Catalyst/SwiftUI 中的错误?使用 Xcode 11.4 和 macOS 10.15.4。

【问题讨论】:

我遇到了类似的问题。我没有添加任何用于处理键盘输入的代码,但我添加了多窗口支持,并且我的催化剂应用程序在按下 Command-n 后继续创建新窗口?还有 xcode 11.4 和 10.15.4 macOS 对于它的价值,我后来发现将 UIKeyCommand 放在 AppDelegate 的 buildMenu(with:) 方法以及 UIHostingController 的 keyCommands 属性中可以防止发生无限触发。这有点重复,但它帮助了我。 谢谢,我会试试的。很高兴听到至少我不是唯一遇到这种情况的人。 我也遇到了同样的问题,一直没找到原因,一直在调用方法-.- @UberJason 自那以后有什么更新吗?我已提交反馈。 【参考方案1】:

我在创建新窗口时遇到了类似的问题。我没有创建任何自定义操作,但我的 iPad 应用程序支持多窗口,所以当我构建 mac 应用程序时,Command-N 只是“工作”。

唯一的问题是它不会停止创建新窗口。最终我发现在我从 Swift 4 -> 5 的迁移中,我得到了一个不正确的 UIApplicationDelegate 回调。所以,appDidFinishLaunching 从未被调用过。

然后我使用自动完成来获得正确的方法签名并解决了我的问题。

这是正确的:func applicationDidFinishLaunching(_ application: UIApplication)

我不确定为什么会导致窗口创建循环,但是两天时间足以浪费在跟踪它上。希望能帮助到那里的人。

【讨论】:

以上是关于使用 SwiftUI 的 Catalyst 应用程序中的键盘命令连续触发的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 将图像保存到 macOS Catalyst

Big Sur 在 SwiftUI Catalyst 中的点击问题

SwiftUI - Catalyst 半透明侧边栏

我可以将 Catalyst 与 MacOS 目标混合使用吗?

SwiftUI - 如何在 macOS 上隐藏窗口标题

Swift UI 列出 Mac Catalyst 上不匹配的部分