我正在做一个 Swift 3 项目,该项目涉及使用一些我从 Objective-C 桥接的 C API。
下面是 API 结构的示例片段:
typedef struct
{
StructMode mode;
StructLevel level;
} TargetStruct;
typedef struct
{
. . .
TargetStruct *targetStruct;
OtherStruct *otherStruct;
NonPointerStructA nonPointerStructA;
NonPointerStructB nonPointerStructB;
. . .
} InnerStruct;
typedef struct
{
InnerStruct innerStruct;
OtherStructB otherStructB;
} OuterStruct;
在我的 Swift 代码中,我的目标是从 OuterStruct 中设置 TargetStruct 的值,如下所示:
// run function that returns an instance of TargetStruct
var targetStruct: TargetStruct = initializeTargetStruct()
// assign targetStruct to outerStruct
outerStruct.innerStruct.targetStruct = &targetStruct
但是,我收到以下错误:
Cannot pass immutable value of TargetStruct as inout argument
如果我设置一个没有 * 的结构值,它将正常工作:
var nonPointerStructA: NonPointerStructA = initializeNonPointerStructA()
outerStruct.innerStruct.nonPointerStructA = nonPointerStructA
我尝试像这样设置 targetStruct 的值,但现在我无法测试它:
var targetStruct: TargetStruct = initializeTargetStruct()
outerStruct.innerStruct.targetStruct.initialize(from: &targetStruct, count: 0)
如何解决这个问题?谢谢。
在 Swift 中,前缀&
不是地址运算符。只需要澄清一些表达式被传递给inout
参数。因此,您的第一个代码在 Swift 中语法无效。
你的 C 结构体被导入到 Swift 中,如下所示:
struct TargetStruct {
var mode: StructMode
var level: StructLevel
//some auto generated initializers...
}
struct InnerStruct {
//...
var targetStruct: UnsafeMutablePointer<TargetStruct>!
var otherStruct: UnsafeMutablePointer<OtherStruct>!
var nonPointerStructA: NonPointerStructA
var nonPointerStructB: NonPointerStructB
//some auto generated initializers...
}
struct OuterStruct {
var innerStruct: InnerStruct
var otherStructB: OtherStructB
//some auto generated initializers...
}
(如果有什么问题,请告诉我。
如您所见,InnerStruct
中的targetStruct
是一个指针,initialize(from:count:)
尝试写入指向的区域,但是在您调用initialize(from:count:)
时,targetStruct
保持其初始值nil
,您知道取消引用空指针时会发生什么。
一种方法是为TargetStruct
分配内存,并使用指向已分配区域的指针。
func allocateAndInitializeTargetStruct() -> UnsafeMutablePointer<TargetStruct> {
let targetStructRef = UnsafeMutablePointer<TargetStruct>.allocate(capacity: 1)
targetStructRef.initialize(to: initializeTargetStruct())
return targetStructRef
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
这是比下面更通用的方法,但您需要显式deinitialize
并deallocate
分配的区域。这有点难以管理。
如果可以将outerStruct
的使用限制在单个代码块中,则可以编写如下内容:
var targetStruct = initializeTargetStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
//Use `outerStruct` only inside this code-block
//...
}
在这种情况下,outerStruct.innerStruct.targetStruct
(==targetStructPtr
( 中持有的指针仅在闭包内部有效,您不能在闭包外部使用它。
如果上述任何代码不适合您的用例,您可能需要提供更多上下文以找到最佳解决方案。
嵌套使用withUnsafeMutablePointer(to:_:)
的示例:
var targetStruct = initializeTargetStruct()
var otherStruct = initializeOtherStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
withUnsafeMutablePointer(to: &otherStruct) {otherStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
outerStruct.innerStruct.otherStruct = otherStructPtr
//Use `outerStruct` only inside this code-block
//...
}
}
当你需要设置更多指针时,这种嵌套会一团糟,但这是 Swift 当前的限制。
deinitialize
和deallocate
的示例:
extension InnerStruct {
func freeMemberStructs() {
if let targetStructRef = targetStruct {
targetStructRef.deinitialize()
targetStructRef.deallocate(capacity: 1)
targetStruct = nil
}
if let otherStructRef = otherStruct {
otherStructRef.deinitialize()
otherStructRef.deallocate(capacity: 1)
otherStruct = nil
}
}
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
outerStruct.innerStruct.otherStruct = allocateAndInitializeOtherStruct()
// Use `outerStruct`
//...
outerStruct.innerStruct.freeMemberStructs()
代码可能看起来不太复杂(只是一堆样板代码(,但很难找到何时何地执行此操作。由于您的InnerStruct
可能嵌入在另一个结构中,因此可能需要deinitilize
d 和deallocate
d...
希望您能找到最佳解决方案。