我正在使用libxml2 C库的Swift 3包装器。
将String
转换为UnsafePointer<xmlChar>
有两种便捷方法,反之亦然。在libxml2 xmlChar
中声明为unsigned char
。
UnsafePointer<xmlChar>
到String
并不复杂
func stringFrom(xmlchar: UnsafePointer<xmlChar>) -> String {
let string = xmlchar.withMemoryRebound(to: CChar.self, capacity: 1) {
return String(validatingUTF8: $0)
}
return string ?? ""
}
对于String
到UnsafePointer<xmlChar>
,我尝试过很多例子
let bytes = string.utf8CString.map{ xmlChar($0) }
return UnsafePointer<xmlChar>(bytes)
但这不起作用,我发现唯一可行的解决方案是
func xmlCharFrom(string: String) -> UnsafePointer<xmlChar> {
let pointer = (string as NSString).utf8String
return unsafeBitCast(pointer, to: UnsafePointer<xmlChar>.self)
}
是否有更好的更快捷的方式,而没有将网桥投射到NSString
和unsafeBitCast
?
答案 0 :(得分:6)
我能想到的最快捷的方法就是使用bitPattern:
初始值设定项:
let xmlstr = str.utf8CString.map { xmlChar(bitPattern: $0) }
这将为您提供Array
xmlChar
个。当您需要将Array
传递给某个内容时,请使用withUnsafeBufferPointer
的{{1}}方法:
UnsafePointer
不要让xmlstr.withUnsafeBufferPointer { someAPIThatWantsAPointer($0.baseAddress!) }
从闭包中逃脱,因为它在它之外是无效的。
UnsafePointer
或者,作为func withXmlString<T>(from string: String, handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
let xmlstr = string.utf8CString.map { xmlChar(bitPattern: $0) }
return try xmlstr.withUnsafeBufferPointer { try handler($0.baseAddress!) }
}
上的扩展程序:
String
答案 1 :(得分:2)
我正在使用一个用于libxml2 C库的Swift 3包装器。
的慰问。
[...]字符串到UnsafePointer [很复杂]
同意。它很复杂,因为不清楚谁拥有xmlChar数组。
[...]我发现的唯一可行解决方案是
let pointer = (string as NSString).utf8String
这是因为-[NSString utf8String]
:
Apple docs:
此C字符串是指向字符串对象内部结构的指针,该字符串对象的生命周期可能短于字符串对象,并且肯定不会有更长的生命周期。
因此,生命周期可能类似于当前的自动释放池,甚至更短,具体取决于编译器的ARC优化和utf8String
的实现。绝对不能保持安全。
是否有更好,更快捷的方式[...]?
嗯,这取决于用例。如果不考虑创建的xmlChar缓冲区的所有权,就无法处理这个问题。
从API中应该清楚函数如何使用传递的字符串(尽管我知道libxml2&#39的文档非常糟糕)。
对于在函数调用期间仅使用字符串的情况,拥有作用域访问函数可能会很好:
extension String {
func withXmlChar(block: (UnsafePointer<xmlChar>) -> ()) { ... }
}
如果函数保持指针周围,则必须保证指针的生命周期。可能类似于容器对象,它保持Data
和指针周围的某些ARC维持生命周期......
通过one of Mike Ash's recent articles可能是值得的,这是关于管理ARC之外的对象的所有权。
答案 2 :(得分:2)
String
有一个
public init(cString: UnsafePointer<UInt8>)
初始化程序,因此从XML字符串到Swift字符串的转换可以简化为
let xmlString: UnsafePointer<xmlChar> = ...
let s = String(cString: xmlString)
错误形成的UTF-8序列被Unicode替换替换
字符U+FFFD
。
对于从Swift字符串到XML字符串的转换,我建议
一个similar approach as Charles Srstka,但使用了
现有的String.withCString
方法,而不是创建中间
阵列:
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
return try self.withCString { try handler(UnsafeRawPointer($0).assumingMemoryBound(to: UInt8.self)) }
}
}
如果不需要投掷选项,则简化为
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) -> T) -> T {
return self.withCString { handler(UnsafeRawPointer($0).assumingMemoryBound(to: UInt8.self)) }
}
}