'UnsafePointer<Int>' 的初始化导致悬空指针

Win*_*ero 5 ios swift

所以我有一些代码来创建 H264ParameterSets,如:

var formatDesc: CMVideoFormatDescription?

func createH264FormatDescription(SPS: Array<UInt8>, PPS: Array<UInt8>) -> OSStatus {
    if formatDesc != nil { formatDesc = nil }

    let paramSet = [UnsafePointer<UInt8>(SPS), UnsafePointer<UInt8>(PPS)]
    let paramPointers = UnsafePointer<UnsafePointer<UInt8>>(paramSet)
    let paramSizes = UnsafePointer<Int>([SPS.count, PPS.count])

    let status = CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault, parameterSetCount: 2, parameterSetPointers: paramPointers, parameterSetSizes: paramSizes, nalUnitHeaderLength: 4, formatDescriptionOut: &formatDesc)

    return status
}
Run Code Online (Sandbox Code Playgroud)

从 Xcode 11.4 开始,我收到了那些 UnsafePointer() 的警告,这在以前似乎没有发生过:

Initialization of UnsafePointer<UInt8> results in a dangling pointer

Initialization of UnsafePointer<UnsafePointer<UInt8>> results in a dangling pointer

Initialization of UnsafePointer<Int> results in a dangling pointer
Run Code Online (Sandbox Code Playgroud)

我不知道为什么我们会看到这个?以及如何删除警告?预先感谢。

bsc*_*ern 5

解释此警告的最简单方法是查看导致它的情况之一。因此,让我们从您使用SPS.

它是一个Array<UInt8>所以它UInt8像在 C 中一样由一个缓冲区支持。当你传递它时SPSUnsafePointer<UInt8>(SPS)它会创建一个指向该缓冲区的有效指针。问题是您可以SPS通过向其附加另一个值来改变say 。这意味着支持 的缓冲区Array可能会移动到内存中的另一个位置。这意味着您现在属于的指针paramSet无效。

另一个问题是,如果您将此指针传递给某个东西,就像您在这种情况下所做的那样,另一个函数可能会尝试保留它,然后它就会有一个无效的指针。因此,如果您希望其他函数保留指针,则需要使用UnsafePointers 和您Unmanaged自己手动管理内存。如果CMVideoFormatDescriptionCreateFromH264ParameterSets()没有抓住指针,那么我将共享的代码是正确的,如果是,您将需要调整它以根据需要创建/销毁内存。

另外值得注意的是,在这种情况下,您不能改变Array您拥有的任何s,因为它们是常量,但通常原理仍然相同。这意味着理论上它永远不会被改变,但 Swift 编译器更喜欢帮助我们编写始终安全且正确的代码,即使是UnsafePointer类型也是如此。

那么你怎么能解决这个问题呢?您将需要能够通过如下方式调用withUnsafeBufferPointer并访问指针UnsafeBufferPointer

var formatDesc: CMVideoFormatDescription?

func createH264FormatDescription(SPS: Array<UInt8>, PPS: Array<UInt8>) -> OSStatus {
    if formatDesc != nil { formatDesc = nil }

    let status = SPS.withUnsafeBufferPointer { SPS in
        PPS.withUnsafeBufferPointer { PPS in
            let paramSet = [SPS.baseAddress!, PPS.baseAddress!]
            let paramSizes = [SPS.count, PPS.count]
            return paramSet.withUnsafeBufferPointer { paramSet in
                paramSizes.withUnsafeBufferPointer { paramSizes in
                    CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault, parameterSetCount: 2, parameterSetPointers: paramSet.baseAddress!, parameterSetSizes: paramSizes.baseAddress!, nalUnitHeaderLength: 4, formatDescriptionOut: &formatDesc)
                }
            }
        }
    }
    return status
}
Run Code Online (Sandbox Code Playgroud)

这种方法之所以有效,是因为withUnsafeBufferPointer排他性法则的范围是保护数组,使它们不能被变异。

如果你所担心的baseAddress!使用情况,您可以检查它不是nil,但可以保证它不会是nilcount > 0根据编译器的工程师(他们在任Twitter或雨燕论坛我忘了...说这一点)。