c - String.withCString when the String is nil



将要描述的问题与我之前的问题有关: string.withCString 和 UnsafeMutablePointer(mutating: cstring) 包装成一个函数,这是我处理 nil 字符串的第一种方法(通过将 withCString 放入函数中) 以及梅基问的一个问题: 为什么我不能传递允许 NULL 指针的可选 Swift 字符串到 C 函数?

想象一下有一个c函数,如下所示:

unsigned long randomSign(char *pin, char *tag_signature, char *tag_data, char *xyz);

我知道如果我在相应的 swift 函数周围包装 4 个字符串.withCString 闭包,该函数可以正常工作:

// pin, tag_signature, tag_data and xyz are optional Strings so they may be nil which is a problem for my result.
// corresponding swift function:
// randomSign(pin: UnsafeMutablePointer<Int8>!, tag_signature: UnsafeMutablePointer<Int8>!, tag_data: UnsafeMutablePointer<Int8>!, xyz: UnsafeMutablePointer<Int8>!)
let result = pin.withCString { s1 in return
tag_signature.withCString {s2 in return
tag_data.withCString {s3 in return
xyz.withCString { s4 in return 
randomSign(UnsafeMutablePointer(mutating: s1), UnsafeMutablePointer(mutating: s2), UnsafeMutablePointer(mutating: s3), UnsafeMutablePointer(mutating: s4))
}}}}

所以Martin R回答了一个更简单的例子,不需要将闭包包装在randomSign(arguments)和UnsafeMutablePointer(mutating:...)周围,因为它也可以接受字符串并转换它。 但是当我放弃闭包并按照 Martin R 的描述使用它时,它在启动 mac 后直接在模拟器上首次启动时工作,但在连续调用 randomSign-Function 时,返回会告诉我例如tag_signature或引脚将是无效的(但它实际上是有效的,我不知道为什么?!

这让我想到了一个问题,即我需要 withCString 闭包(目前),但我必须处理 nil-Strings,这将导致应用程序在返回结果时崩溃,因为它无法评估 randomSign-Function。

所以我试图将下面的方法(也是 @Martin R 建议的)适应 Swift 3,但我没有努力适应它。

//Swift-2 written by Martin R
protocol CStringConvertible {
func withCString<Result>(@noescape f: UnsafePointer<Int8> throws -> Result) rethrows -> Result
}
extension String: CStringConvertible { }
extension Optional where Wrapped: CStringConvertible {
func withOptionalCString<Result>(@noescape f: UnsafePointer<Int8> -> Result) -> Result {
if let string = self {
return string.withCString(f)
} else {
return f(nil)
}
}
}
//Swift 3: ???

如果有人能告诉我,为什么我的函数只在我使用 CString 时才起作用,而在我关闭它时不起作用,我将不胜感激 以及是否有人知道如何解决问题,即将 swift-2 代码正确转换为工作 swift-3 代码。

问题

let result = randomSign(UnsafeMutablePointer(mutating: pin),
UnsafeMutablePointer(mutating: tag_signature),
UnsafeMutablePointer(mutating: tag_data),
UnsafeMutablePointer(mutating: xyz))

是从 Swift 创建的临时 UTF-8 表示 字符串仅在每次调用UnsafeMutablePointer()期间有效, 但在randomSign()召唤期间不一定仍然有效。 (所以我在 https://stackoverflow.com/a/44027397/1187415 的最后一个建议 实际上不正确,我已经更新了该部分)。

https://stackoverflow.com/a/39363769/1187415 中包装器的可能 Swift 3 版本是

extension Optional where Wrapped == String {
func withOptionalCString<Result>(_ f: (UnsafeMutablePointer<Int8>?) -> Result) -> Result {
if let string = self {
return string.withCString { f(UnsafeMutablePointer(mutating: $0)) }
} else {
return f(nil)
}
}
}

这将处理可选性强制转换 C 字符串指针 到可变指针(根据randomSign()的要求)。这可以是 称为

let result = pin.withOptionalCString { s1 in
tag_signature.withOptionalCString { s2 in
tag_data.withOptionalCString { s3 in
xyz.withOptionalCString { s4 in
randomSign(s1, s2, s3, s4)
}
}
}
}

备注:理论上,如果将randomSign()的签名更改为采用const char *参数,则可以避免该问题:

unsigned long randomSign(const char *pin, const char *tag_signature, const char *tag_data, const char *xyz);

然后可以简单地称为

let result = randomSign(pin, tag_signature, tag_data, xyz)

使用可选或非可选的 Swift 字符串。 但是,这目前不起作用,如 SR-2814 Swift 无法正确将多个可选字符串传递给 C 函数。

相关内容

最新更新