1

我正在将 Swift MacOS 命令行工具/守护进程转换为使用 Swift-NIO 进行网络连接。这是我的第一个 Swift-NIO 项目。

该工具每 0.1 秒触发一次计时器。这是在 Swift-NIO 转换之前启动守护程序/运行循环的 main.swift 底部的行:

RunLoop.current.run()

这是我的 Universe.swift 类 init() 中的计时器。这个类总是只有一个实例:

    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)
    }

在此配置中,计时器按预期每秒触发 10 次。但是如果我得到任何网络输入,我的 Swift-NIO 库就会崩溃,因为它不在预期的事件循环中。

在此处输入图像描述 在 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()

这解决了 Swift-NIO 崩溃,但是我从来没有到达我的计时器 RunLoop,所以我的计时器没有触发。

如何使用 Swift-NIO 接收(和发送)网络数据,同时仍然有一个计时器运行?

如果有帮助,该项目的完整开源代码位于https://github.com/darrellroot/netrek-server-swift

4

1 回答 1

0

卢卡萨是对的。我错过了(并且不理解)一些重要的背景。

我的计时器最终尝试使用 SwiftNIO 发送数据,如下所示:

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

解决方法是将流量“分派”到与上下文相关的 EventLoop:

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

感觉很像 DispatchQueue.main.async { } 用于更新 iOS 应用程序中的 GUI,但使用不同的 Swift-NIO 相关术语。

于 2020-07-09T22:49:13.270 回答