我基本上试图将 C 结构包装在 Swift 类中。
Swift 类有一个 C 结构类型的实例属性。
C 结构包含多个 const char *
类型的属性。
为了给结构赋值,我为每个属性编写了 getter 和 setter:
public class MyClass: NSObject {
private var configuration = c_structure_config()
}
// Function of MyClass
// f.ex. on "registrationUri:"
private(set) public var registrationUri: String {
get {
return String(cString: configuration.reg_uri)
}
set {
if (configuration.reg_uri != nil) {
configuration.reg_uri.deallocate()
}
let maxLength = newValue.count + 1 // +1 for NULL
var buffer: [CChar] = [CChar](UnsafeMutableBufferPointer<Int8>.allocate(capacity: maxLength))
guard newValue.getCString(&buffer, maxLength: maxLength, encoding: .utf8) == true else {
fatalError("Could not allocate memory for Account Config reg uri")
}
// "configuration" is the instance property (see above)
// reg_uri is of type char const *
configuration.reg_uri = UnsafePointer<Int8>(buffer)
}
}
但是,这种方法会导致奇怪的崩溃和错误报告,提示指针重叠范围( fatal error :UnsafeMutablePointer.initialize重叠范围
)。
我知道每当设置字符串时我都会释放和分配内存,但这可能不是很有效。不过到目前为止我还没有找到更好的解决方案。
这里出了什么问题(或者这是对的,我做了一个错误的假设,我必须在其他地方搜索)?
最佳答案
您的解决方案存在一些问题。
首先,使用String.count
来计数来获取底层C缓冲区的大小是不明智的。原因是 String.count
返回字符串的实际字符数,而不是用于表示它的字节数。并非所有字符都适合 Int8
(又名 CChar
)的 256 位。因此,如果您尝试使用非 ASCII 字符设置属性,您的代码可能会崩溃。最好使用 String.utf8CString
属性,它返回 CChar
的连续数组。
其次,由于您的缓冲区是在 setter 内分配的,因此当您的 setter 返回时,它将被释放(Swift 数组是值类型的实例,其生命周期受堆栈约束)。这意味着当您的 setter 返回时,与 buffer 的基址对应的指针实际上已失效。我怀疑这就是您报告的错误在运行时发生的原因。
最后,请不要在守卫和 if 语句中测试 true
。
这是更正后的版本:
var registrationUri: String {
get {
return String(cString: reg_uri)
}
set {
if (reg_uri != nil) {
reg_uri.deallocate()
}
newValue.withCString { cString in
// No need to add 1, newValue.utf8CString already has the correct buffer capacity.
let capacity = newValue.utf8CString.count
let buffer: UnsafeMutablePointer<Int8> = .allocate(capacity: capacity)
buffer.assign(from: cString, count: capacity)
reg_uri = UnsafePointer(buffer)
}
}
}
// ...
myInstance.registrationUri = "こんいちは"
print(myInstance.registrationUri)
// Prints "こんいちは"
关于c - 如何在 Swift 中复制指向数组的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57058778/