将要描述的问题与我之前的问题有关: string.withCString and UnsafeMutablePointer(mutating: cstring) wrapped into a function这是我处理nil Strings的第一种方法(通过将withCString放入函数中) 以及Mecki问的一个问题: Why can't I pass an optional Swift String to C function that allows NULL pointers?
想象一下有一个c函数,如:
unsigned long randomSign(char *pin, char *tag_signature, char *tag_data, char *xyz);
我知道如果我在相应的swift函数周围包装4个string.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))
}}}}
And so Martin R replied to an easier example,不需要在randomSign(arguments)和UnsafeMutablePointer(mutating:...)周围包装闭包,因为它也可以接受字符串并转换它。 但是当我删除闭包并将其用作Martin R described时,它在启动mac后直接在模拟器上启动时工作,但是在randomSign-Function的连续调用中,返回会告诉我例如tag_signature或者引脚无效(但它实际上是有效的,我不知道为什么?!)。
这引出了我需要withCString闭包的问题(目前)但我必须处理nil-Strings,这会导致应用程序在返回结果时崩溃,因为它无法评估randomSign-Function。
所以我试图让the approach below (also suggested by @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: ???
如果有人能告诉我,为什么我的功能只有在我使用withCString时才能解决,但是当我解除它时,我会非常感激 如果有人知道如何解决这个问题,即正确地将swift-2代码翻译成工作的swift-3代码。
答案 0 :(得分:0)
的问题
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 does not correctly pass in multiple optional strings to C function