Swift 5.10 关于“可能不正确”的警告对于可选的“CFType”实际上是不正确的吗?

问题描述 投票:0回答:1

我有一些代码开始生成有关我在 Swift 5.10(可能更早)中使用

&
运算符的警告。

将“UnsafeMutableRawPointer”形成为“Optional”类型的变量;这可能是不正确的,因为“可选”可能包含对象引用。

public func bad(audioObject: AudioObjectID) {
    var propAddr = AudioObjectPropertyAddress()
    
    var x: CFString!
    var size = UInt32(MemoryLayout.size(ofValue: x))
    
    let _ = AudioObjectGetPropertyData(audioObject, &propAddr, 0, nil, &size, &x)
    //                                                                        ^
    // Forming 'UnsafeMutableRawPointer' to a variable of type 'Optional<CFString>'; this is likely incorrect because 'Optional<CFString>' may contain an object reference.

}

所以我机械地将代码转换为产生该警告,但我不明白有什么区别,也不明白原始版本是否确实隐藏了错误。

func good(audioObject: AudioObjectID) {
    var propAddr = AudioObjectPropertyAddress()

    var x: CFString!
    var size = UInt32(MemoryLayout.size(ofValue: x))
    
    let _ = withUnsafeMutablePointer(to: &x) { pointerToX in
        return AudioObjectGetPropertyData(audioObject, &propAddr, 0, nil, &size, pointerToX)
    }
}

那么“坏”版本“可能”出了什么问题,为什么“好”版本没有问题?

swift core-foundation
1个回答
0
投票
this commit

添加的。当您将非平凡类型隐式转换为原始指针时,会发出此警告。提交消息显示:

例如,支持这种转换结果很糟糕:

void read_void(const void *input); func foo(data: inout Data) { read_void(&data) }

人们期望 Foundation.Data 具有相同的类型是可以理解的
隐式转换为数组。但它做了一些非常错误的事情
相反。

这个想法是,人们经常误解这个
&

转换的作用,并使用它来调用直接从具有非平凡类型的指针读取数据的函数。例如,在上面的示例中,

read_void(&data)
不会
将指针传递到
Data所保存的实际缓冲区(在堆中)。这样形成的指针只会指向栈上的参数。 Data
 结构本身包含一个指向实际缓冲区的指针,应该使用 
Data.withUnsafeBytes
 来获取该指针并将其传递给 
read_void
这就是错误消息提到“可能包含对象引用”的原因。它本质上是说“对于您实际想要传递的数据可能还有进一步的间接层”。

当然,以

CFString

为例,您知道自己在做什么,并且

AudioObjectGetPropertyData

 也知道它在做什么。您知道原始指针不会像缓冲区一样被读取,并且该函数只会向其写入 
CFString
通过使用
withUnsafeMutablePointer

,您可以更清楚地表达这一意图。您明确表示您想要一个指向堆栈上

CFString

 值的指针,而不是其内容。

© www.soinside.com 2019 - 2024. All rights reserved.