我正在与C API交互。为了内存安全,我选择不内部保留C类型,而仅在另一个C api需要它们时才产生它们,因此我可以使用普通的Swift结构。在此示例中,我仅使用Foo
类型作为替代,显然这不是真实类型。
现在,当我需要调用C API时,我在类型上有这两个方法,可以生成可以使用的C指针:
struct Foo {
let bar: Int
}
extension Optional where Wrapped == Foo {
func withUnsafePointer<T>(_ block: (Foo?) throws -> T) rethrows -> T {
guard let self = self else {
return try block(nil)
}
return try block(self)
}
}
extension Foo {
func withUnsafePointer<T>(_ block: (Foo) throws -> T) rethrows -> T {
return try block(self)
}
}
如您所见,我还需要扩展可选内容以方便实现。否则,将不会执行对foo?.withUnsafePointer(...)
的调用。
我觉得这种模式不是特别漂亮。有没有更好的选择,而不是两次执行该方法?
整个问题是,C对象的生存期应该有限(在块内)。
答案 0 :(得分:2)
通过声明协议,使withUnsafePointer
和Foo
都符合该协议,然后扩展该协议,可以避免重复Foo?
方法。这不一定像extension Foo, Optional<Foo>
那样漂亮,但是截至本文撰写之时,AFAIK目前还没有一种方法可以在Swift中完成。
struct Foo {
let myCPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
}
protocol HasMyCPointer {
associatedtype MyCPointerType
var myCPointer: MyCPointerType { get }
}
extension Foo: HasMyCPointer {}
extension Optional: HasMyCPointer where Wrapped == Foo {
var myCPointer: UnsafeMutablePointer<UInt8>? { self?.myCPointer }
}
extension HasMyCPointer {
func withUnsafePointer<T>(_ block: (Self.MyCPointerType) throws -> T) rethrows -> T {
return try block(self.myCPointer)
}
}
let foo = Foo()
let bar: Foo? = nil
let baz: Foo? = Foo()
foo.withUnsafePointer {
print("Foo: \($0)")
}
bar.withUnsafePointer {
print("Bar: \($0 as Any)")
}
baz.withUnsafePointer {
print("Baz: \($0 as Any)")
}
打印:
Foo: 0x00007fade3c05750
Bar: nil
Baz: Optional(0x00007fade3c00220)