简体   繁体   English

在使用 Swift-NIO 进行联网的 MacOS 命令行工具/守护程序中使用 Swift 计时器:RunLoop 与等待问题

[英]Using a Swift Timer in a MacOS command-line-tool / daemon which uses Swift-NIO for networking: RunLoop vs wait issue

I'm converting a Swift MacOS command-line tool/daemon to use Swift-NIO for networking.我正在转换 Swift MacOS 命令行工具/守护程序以使用 Swift-NIO 进行网络连接。 This is my first Swift-NIO project.这是我的第一个 Swift-NIO 项目。

The tool fires a timer every 0.1 second.该工具每 0.1 秒触发一次计时器。 Here's the line at the bottom of main.swift which fires up the daemon/runloop, prior to the Swift-NIO conversion:这是 main.swift 底部的行,它在 Swift-NIO 转换之前启动守护程序/运行循环:

RunLoop.current.run()

Here's the timer in my Universe.swift class init().这是我的 Universe.swift class init() 中的计时器。 There is always exactly one instance of this class:这个 class 总是只有一个实例:

    timer = Timer(timeInterval: 1.0 / updatesPerSecond, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
    timer?.tolerance = 0.3 / updatesPerSecond
    debugPrint("Timer initialized")
    if let timer = timer {
        RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
    }

In this configuration the timer fires 10 times per second as expected.在此配置中,计时器按预期每秒触发 10 次。 But if I get any network input my Swift-NIO library crashes because its not in the expected event loop.但是如果我得到任何网络输入,我的 Swift-NIO 库就会崩溃,因为它不在预期的事件循环中。

在此处输入图像描述 In Swift-NIO, I'm supposed to add a channel.closeFuture.wait() line to the bottom of my main.swift:在 Swift-NIO 中,我应该在 main.swift 的底部添加一条 channel.closeFuture.wait() 行:

// This will never unblock as we don't close the ServerChannel.
try channel.closeFuture.wait()
RunLoop.current.run()

That solves the Swift-NIO crash, but then I never get to my timer RunLoop, so my timer doesn't fire.这解决了 Swift-NIO 崩溃,但是我从来没有到达我的计时器 RunLoop,所以我的计时器没有触发。

How can I use Swift-NIO to receive (and send) network data, while still having a timer running?如何使用 Swift-NIO 接收(和发送)网络数据,同时仍然有一个计时器运行?

If it helps, the full open source for this project is at https://github.com/darrellroot/netrek-server-swift .如果有帮助,该项目的完整开源代码位于https://github.com/darrellroot/netrek-server-swift

Lukasa was right.卢卡萨是对的。 I was missing (and not understanding) some important context.我错过了(并且不理解)一些重要的背景。

My timer was eventually trying to send data using SwiftNIO like so:我的计时器最终尝试使用 SwiftNIO 发送数据,如下所示:

    if let context = context {
        let buffer = context.channel.allocator.buffer(bytes: data)
        _ = context.channel.writeAndFlush(buffer)
    }

The fix was to "dispatch" the sending of the traffic to the context-related EventLoop:解决方法是将流量“分派”到与上下文相关的 EventLoop:

    if let context = context {
        context.eventLoop.execute {
                let buffer = context.channel.allocator.buffer(bytes: data)
                _ = context.channel.writeAndFlush(buffer)
        }
    }

It feels very similar to DispatchQueue.main.async { } for updating the GUI in iOS apps, but with different Swift-NIO related terminology.感觉非常类似于 DispatchQueue.main.async { } 用于更新 iOS 应用程序中的 GUI,但使用不同的 Swift-NIO 相关术语。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM