当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Swift UnsafeMutablePointer用法及代码示例


结构

UnsafeMutablePointer

用于访问和操作特定类型数据的指针。

声明

@frozen struct UnsafeMutablePointer<Pointee>

概述

您使用UnsafeMutablePointer 类型的实例来访问内存中特定类型的数据。指针可以访问的数据类型是指针的Pointee 类型。 UnsafeMutablePointer 不提供自动内存管理或对齐保证。您负责通过不安全的指针处理您使用的任何内存的生命周期,以避免泄漏或未定义的行为。

您手动管理的内存可以是特定类型的untypedbound。您使用UnsafeMutablePointer 类型来访问和管理已绑定到特定类型的内存。

了解指针的内存状态

UnsafeMutablePointer 实例引用的内存可以处于多种状态之一。许多指针操作只能应用于内存处于特定状态的指针——您必须跟踪正在使用的内存的状态,并了解不同操作执行的对该状态的更改。内存可以是无类型的和未初始化的,绑定到一个类型但未初始化,或者绑定到一个类型并初始化为一个值。最后,先前分配的内存可能已被释放,留下现有指针引用未分配的内存。

未初始化的内存

刚刚通过类型化指针分配或已取消初始化的内存处于uninitialized 状态。必须先初始化未初始化的内存,然后才能访问它以进行读取。

您可以使用 initialize(repeating:count:)initialize(from:count:)moveInitialize(from:count:) 之类的方法来用一个值或一系列值初始化指针所引用的内存。

初始化内存

Initialized 内存具有可以使用指针的 pointee 属性或通过下标表示法读取的值。在下面的示例中,ptr 是一个指向内存的指针,初始化为 23


let ptr: UnsafeMutablePointer<Int> = ...
// ptr.pointee == 23
// ptr[0] == 23

以不同类型访问指针的内存

通过UnsafeMutablePointer实例访问内存时,Pointee类型必须与内存的绑定类型一致。如果您确实需要将绑定到一种类型的内存作为不同类型访问,Swift 的指针类型提供了type-safe 方法来临时或永久更改内存的绑定类型,或者直接从原始内存加载类型化实例。

分配有八字节内存的 UnsafeMutablePointer<UInt8> 实例 uint8Pointer 将用于以下示例。


var bytes: [UInt8] = [39, 77, 111, 111, 102, 33, 39, 0]
let uint8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: 8)
uint8Pointer.initialize(from: &bytes, count: 8)

当您只需要临时以不同类型访问指针的内存时,请使用withMemoryRebound(to:capacity:) 方法。例如,您可以使用此方法调用 API,该 API 需要指向与您的指针的 Pointee 布局兼容的不同类型的指针。下面的代码临时将uint8Pointer引用的内存从UInt8重新绑定到Int8,以调用导入的Cstrlen函数。


// Imported from C
func strlen(_ __s: UnsafePointer<Int8>!) -> UInt


let length = uint8Pointer.withMemoryRebound(to: Int8.self, capacity: 8) {
    return strlen($0)
}
// length == 7

当您需要将内存永久重新绑定到不同类型时,首先获取指向内存的原始指针,然后在原始指针上调用bindMemory(to:capacity:) 方法。以下示例将 uint8Pointer 引用的内存绑定到 UInt64 类型的一个实例:


let uint64Pointer = UnsafeMutableRawPointer(uint8Pointer)
                          .bindMemory(to: UInt64.self, capacity: 1)

在将 uint8Pointer 引用的内存重新绑定到 UInt64 后,作为 UInt8 实例访问该指针的引用内存是未定义的。


var fullInteger = uint64Pointer.pointee          // OK
var firstByte = uint8Pointer.pointee             // undefined

或者,只要绑定类型和目标类型是普通类型,您就可以访问相同的内存作为不同类型,而无需通过非类型化内存访问重新绑定。将指针转换为 UnsafeMutableRawPointer 实例,然后使用原始指针的 load(fromByteOffset:as:)storeBytes(of:toByteOffset:as:) 方法读取和写入值。


let rawPointer = UnsafeMutableRawPointer(uint64Pointer)
let fullInteger = rawPointer.load(as: UInt64.self)   // OK
let firstByte = rawPointer.load(as: UInt8.self)      // OK

执行类型化指针算术

具有类型化指针的指针算术以指针的Pointee 类型的步长计数。当您添加到 UnsafeMutablePointer 实例或从 UnsafeMutablePointer 实例减去时,结果是相同类型的新指针,偏移量为 Pointee 类型的实例数。


// 'intPointer' points to memory initialized with [10, 20, 30, 40]
let intPointer: UnsafeMutablePointer<Int> = ...


// Load the first value in memory
let x = intPointer.pointee
// x == 10


// Load the third value in memory
let offsetPointer = intPointer + 2
let y = offsetPointer.pointee
// y == 30

您还可以使用下标表示法来访问内存中特定偏移量的值。


let z = intPointer[2]
// z == 30

隐式转换和桥接

当使用 UnsafeMutablePointer 参数调用函数或方法时,您可以传递该特定指针类型的实例或使用 Swift 的隐式桥接来传递兼容的指针。

例如,以下代码示例中的 printInt(atAddress:) 函数需要一个 UnsafeMutablePointer<Int> 实例作为其第一个参数:


func printInt(atAddress p: UnsafeMutablePointer<Int>) {
    print(p.pointee)
}

与 Swift 中的典型情况一样,您可以使用 UnsafeMutablePointer 实例调用 printInt(atAddress:) 函数。此示例将 intPointer (指向 Int 值的可变指针)传递给 print(address:)


printInt(atAddress: intPointer)
// Prints "42"

或者,您可以使用 Swift 的 implicit bridging 将指针传递给实例或数组的元素。以下示例使用 inout 语法传递指向 value 变量的指针:


var value: Int = 23
printInt(atAddress: &value)
// Prints "23"

使用 inout 语法传递数组时,会隐式创建指向数组元素的可变指针。此示例在调用 printInt(atAddress:) 时使用隐式桥接将指针传递给 numbers 的元素。


var numbers = [5, 10, 15, 20]
printInt(atAddress: &numbers)
// Prints "5"

无论你以哪种方式调用 printInt(atAddress:) ,Swift 的类型安全保证你只能传递一个指向函数所需类型的指针——在本例中,是一个指向 Int 的指针。

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相关用法


注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 UnsafeMutablePointer。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。