将要描述的问题与我之前的问题有关:string.withCString和UnsafeMutablePointer(变异: cstring)被包装成一个函数,这是我第一次处理零字符串(通过将withCString放入函数),以及Mecki问的一个问题:为什么我不能将一个允许空指针的可选Swift字符串传递给C函数呢?
假设有一个c-函数,类似于:
unsigned long randomSign(char *pin, char *tag_signature, char *tag_data, char *xyz);我知道,如果围绕相应的string.withCString函数包装4个闭包,该函数就能正常工作:
// 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))
}}}}马丁R回答了一个更简单的例子,它不需要围绕randomSign(参数)和UnsafeMutablePointer(变异:.)包装闭包。因为它也可以接受字符串并对其进行转换。但是,当我放弃闭包并使用它作为马丁·R时,它在启动mac后第一次在模拟器上启动时就工作了,但是在随机信号函数的连续调用中,返回会告诉我,例如,tag_signature或引脚将是无效的(但它实际上是有效的,我不知道为什么?!)
这就引出了我需要withCString闭包的问题(目前),但我必须处理零字符串,这将导致应用程序在返回结果时崩溃,因为它无法评估随机函数。
所以我试着把以下方法( @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时才能工作,而当我不接受它时,我会非常感激,如果有人知道如何解决这个问题,也就是正确地将SWIFE-2代码转换成工作的also 3代码的话。
发布于 2017-05-19 09:43:55
问题在于
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函数中所报告的,这种方法目前不起作用。
https://stackoverflow.com/questions/44065751
复制相似问题