现在我们已经达到了 Swift 2.0,我决定将我尚未完成的 OS X 应用程序转换为 Swift。取得了进展,但我在使用 termios 时遇到了一些问题,需要一些澄清和建议。
termios 结构在 Swift 中被视为结构,这并不奇怪,但令人惊讶的是结构中的控制字符数组现在是一个元组。我原以为它只是一个数组。正如你可能想象的那样,我花了一段时间才弄清楚这一点。如果我在游乐场工作:
var settings:termios = termios()
print(settings)
然后我会打印该结构的正确详细信息。
在 Obj-C 中设置您将使用的控制字符,例如,
cfmakeraw(&settings);
settings.c_cc[VMIN] = 1;
其中
VMIN
是 termios.h 中等于 16 的 #define。在 Swift 中我必须做
cfmakeraw(&settings)
settings.c_cc.16 = 1
它有效,但有点不透明。我更喜欢使用类似的东西
settings.c_cc.vim = 1
相反,但似乎找不到任何描述 termios 的 Swift“版本”的文档。有谁知道元组是否为其元素预先分配了名称,或者如果没有,是否有办法在事后分配名称?我应该使用命名元素创建自己的元组,然后将其分配给
settings.c_cc
吗?
有趣的是,尽管事实上预处理器指令不应该在 Swift 中工作,但如果我这样做的话
print(VMIN)
print(VTIME)
然后打印正确的值并且不会产生编译器错误。我有兴趣对此进行任何澄清或评论。这是一个错误吗?
剩下的问题与 termios 的进一步配置有关。
cfsetspeed
的定义为
func cfsetspeed(_: UnsafeMutablePointer<termios>, _: speed_t) -> Int32
和
speed_t
被类型定义为无符号长整型。在 Obj-C 中我们会这样做
cfsetspeed(&settings, B38400);
但是由于
B38400
是 termios.h 中的 #define,我们不能再这样做了。 Apple 是否在 Swift 中为此类内容设置了替换全局常量,如果是,谁能告诉我它们的记录在哪里。另一种选择似乎是只插入原始值并失去可读性,或者创建我自己的先前在 termios.h 中定义的常量版本。如果没有更好的选择,我很乐意走这条路。
让我们从第二个问题开始,这个问题更容易解决。
B38400
is 在 Swift 中可用,只是类型错误。
所以你必须明确地转换它:
var settings = termios()
cfsetspeed(&settings, speed_t(B38400))
据我所知,你的第一个问题没有“好的”解决方案。 固定大小的数组作为元组导入到 Swift 中,并且据我所知,您不能使用 variable 来寻址元组元素。
但是,Swift 保留从 C 导入的结构的内存布局,如 经苹果工程师 Joe Groff 确认:。因此,您可以获取元组的地址并将其“重新绑定”到指向元素类型的指针:
var settings = termios()
withUnsafeMutablePointer(to: &settings.c_cc) { (tuplePtr) -> Void in
tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: settings.c_cc)) {
$0[Int(VMIN)] = 1
}
}
(针对 Swift 4+ 更新了代码。)
因为
c_cc
是一个字节数组,例如[UInt8]
,您可以执行以下操作
var tty = termios()
withUnsafeMutableBytes(of: &tty.c_cc)
{
c_cc in
c_cc[size_t(VMIN)] = 1
c_cc[size_t(VTIME)] = 0
}