在 Swift 3 (libxml2) 中将 String 转换为 UnsafePointer<xmlChar> 的更快捷的方法
A swiftier way to convert String to UnsafePointer<xmlChar> in Swift 3 (libxml2)
我正在为 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: [=12=])
}
return string ?? ""
}
对于String
到UnsafePointer<xmlChar>
我尝试了很多东西例如
let bytes = string.utf8CString.map{ xmlChar([=13=]) }
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
?
我能想到的最快捷的方法就是使用 bitPattern:
初始值设定项:
let xmlstr = str.utf8CString.map { xmlChar(bitPattern: [=13=]) }
这将为您提供 Array
个 xmlChar
秒。坚持下去,当你需要将 UnsafePointer
传递给某物时,使用 Array
的 withUnsafeBufferPointer
方法:
xmlstr.withUnsafeBufferPointer { someAPIThatWantsAPointer([=19=].baseAddress!) }
不要让 UnsafePointer
从闭包中逃逸,因为它在闭包之外是无效的。
编辑:这是如何妥协的?不要让你的函数 return 成为一个指针,而是让它闭包。
func withXmlString<T>(from string: String, handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
let xmlstr = string.utf8CString.map { xmlChar(bitPattern: [=10=]) }
return try xmlstr.withUnsafeBufferPointer { try handler([=10=].baseAddress!) }
}
或者,作为 String
的扩展:
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
let xmlstr = self.utf8CString.map { xmlChar(bitPattern: [=11=]) }
return try xmlstr.withUnsafeBufferPointer { try handler([=11=].baseAddress!) }
}
}
I'm working on a Swift 3 wrapper for the libxml2 C-library.
表示哀悼。
[...] String to UnsafePointer [is complicated]
同意。这很复杂,因为不清楚谁拥有 xmlChar 数组。
[...] the only working solution I figured out is
let pointer = (string as NSString).utf8String
这是因为 -[NSString utf8String]
:
的所有权语义
Apple 文档:
This C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime.
所以生命周期可能类似于当前的自动释放池甚至更短,这取决于编译器的 ARC 优化和 utf8String
的实现。随身携带绝对不安全。
Is there a better, swiftier way [...]?
好吧,这取决于用例。如果不考虑创建的 xmlChar 缓冲区的所有权,就无法处理这个问题。
从 API 中可以清楚地看出函数是如何使用传递的字符串的(即使我知道 libxml2 的文档很糟糕)。
对于仅在函数调用期间使用字符串的情况,使用作用域访问函数可能会更好:
extension String {
func withXmlChar(block: (UnsafePointer<xmlChar>) -> ()) { ... }
}
如果函数保留指针,则必须保证指针对象的生命周期。可能类似于容器对象,它在某个 ARC 维护的生命周期内保持 Data
和指针...
可能值得通读 one of Mike Ash's recent articles,这是关于管理 ARC 之外的对象的所有权。
String
有一个
public init(cString: UnsafePointer<UInt8>)
初始化器,因此从XML字符串到Swift字符串的转换可以简化为
let xmlString: UnsafePointer<xmlChar> = ...
let s = String(cString: xmlString)
错误格式的 UTF-8 序列被替换为 Unicode 替换
字符 U+FFFD
.
对于从 Swift 字符串到 XML 字符串的转换,我建议
,但使用
现有 String.withCString
方法而不是创建中间方法
数组:
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
return try self.withCString { try handler(UnsafeRawPointer([=12=]).assumingMemoryBound(to: UInt8.self)) }
}
}
如果不需要投掷选项,则简化为
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) -> T) -> T {
return self.withCString { handler(UnsafeRawPointer([=13=]).assumingMemoryBound(to: UInt8.self)) }
}
}
我正在为 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: [=12=]) } return string ?? "" }
对于
String
到UnsafePointer<xmlChar>
我尝试了很多东西例如let bytes = string.utf8CString.map{ xmlChar([=13=]) } 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
?
我能想到的最快捷的方法就是使用 bitPattern:
初始值设定项:
let xmlstr = str.utf8CString.map { xmlChar(bitPattern: [=13=]) }
这将为您提供 Array
个 xmlChar
秒。坚持下去,当你需要将 UnsafePointer
传递给某物时,使用 Array
的 withUnsafeBufferPointer
方法:
xmlstr.withUnsafeBufferPointer { someAPIThatWantsAPointer([=19=].baseAddress!) }
不要让 UnsafePointer
从闭包中逃逸,因为它在闭包之外是无效的。
编辑:这是如何妥协的?不要让你的函数 return 成为一个指针,而是让它闭包。
func withXmlString<T>(from string: String, handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
let xmlstr = string.utf8CString.map { xmlChar(bitPattern: [=10=]) }
return try xmlstr.withUnsafeBufferPointer { try handler([=10=].baseAddress!) }
}
或者,作为 String
的扩展:
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
let xmlstr = self.utf8CString.map { xmlChar(bitPattern: [=11=]) }
return try xmlstr.withUnsafeBufferPointer { try handler([=11=].baseAddress!) }
}
}
I'm working on a Swift 3 wrapper for the libxml2 C-library.
表示哀悼。
[...] String to UnsafePointer [is complicated]
同意。这很复杂,因为不清楚谁拥有 xmlChar 数组。
[...] the only working solution I figured out is
let pointer = (string as NSString).utf8String
这是因为 -[NSString utf8String]
:
Apple 文档:
This C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime.
所以生命周期可能类似于当前的自动释放池甚至更短,这取决于编译器的 ARC 优化和 utf8String
的实现。随身携带绝对不安全。
Is there a better, swiftier way [...]?
好吧,这取决于用例。如果不考虑创建的 xmlChar 缓冲区的所有权,就无法处理这个问题。
从 API 中可以清楚地看出函数是如何使用传递的字符串的(即使我知道 libxml2 的文档很糟糕)。
对于仅在函数调用期间使用字符串的情况,使用作用域访问函数可能会更好:
extension String {
func withXmlChar(block: (UnsafePointer<xmlChar>) -> ()) { ... }
}
如果函数保留指针,则必须保证指针对象的生命周期。可能类似于容器对象,它在某个 ARC 维护的生命周期内保持 Data
和指针...
可能值得通读 one of Mike Ash's recent articles,这是关于管理 ARC 之外的对象的所有权。
String
有一个
public init(cString: UnsafePointer<UInt8>)
初始化器,因此从XML字符串到Swift字符串的转换可以简化为
let xmlString: UnsafePointer<xmlChar> = ...
let s = String(cString: xmlString)
错误格式的 UTF-8 序列被替换为 Unicode 替换
字符 U+FFFD
.
对于从 Swift 字符串到 XML 字符串的转换,我建议
String.withCString
方法而不是创建中间方法
数组:
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) throws -> T) rethrows -> T {
return try self.withCString { try handler(UnsafeRawPointer([=12=]).assumingMemoryBound(to: UInt8.self)) }
}
}
如果不需要投掷选项,则简化为
extension String {
func withXmlString<T>(handler: (UnsafePointer<xmlChar>) -> T) -> T {
return self.withCString { handler(UnsafeRawPointer([=13=]).assumingMemoryBound(to: UInt8.self)) }
}
}