Swift中有4個指針類型:UnsafePointer
、UnsafeMutablePointer
、UnsafeRawPointer
、UnsafeMutableRawPointer
,通過指針可以直接修改指向的內存數據,下面簡單介紹下它們的幾個常見用法。
一、從已有的變量獲取指針
- 獲取指向變量或者指向對象的指針、讀寫指向變量的值的方式如下:
var age = 10
// 通過withUnsafeXXXXPointer創建指向變量或對象的指針
func testGetPointer() {
// 1.指向值類型變量時
var ptr1 = withUnsafePointer(to: &age, { $0 })
var ptr2 = withUnsafeMutablePointer(to: &age, { $0 })
// ptr1.pointee = 15 // ptr1不可變,這裏報錯
ptr2.pointee = 20
print("ptr1=\(ptr1.pointee), ptr2=\(ptr2.pointee)") // 都是20
// 使用原始指針
var ptr3 = withUnsafePointer(to: &age, { UnsafeRawPointer($0) })
var ptr4 = withUnsafeMutablePointer(to: &age, { UnsafeMutableRawPointer($0) })
ptr4.storeBytes(of: 50, as: Int.self)
print("ptr3=\(ptr3.load(as: Int.self)), ptr4=\(ptr4.load(as: Int.self))") // 都是50
// 2.指向對象時
var hba = HBA(no: "no119", name: "name120")
let ptr5 = withUnsafePointer(to: &hba, { $0 })
let ptr6 = withUnsafeMutablePointer(to: &hba, { $0 })
ptr6.pointee.no = "no911"
print("no=\(ptr5.pointee.no),name=\(ptr5.pointee.name)") // no=no911,name=name120
// 原始指針
var ptr7 = withUnsafePointer(to: &hba, { UnsafeRawPointer($0) })
// var ptr8 = withUnsafeMutablePointer(to: &hba, { UnsafeMutableRawPointer($0) })
// ptr7、ptr8的值是hba指針的地址值,要訪問到hba對象的堆空間地址值還需要如下操作
// 根據bitPattern參數(堆空間地址)初始化一個指針
var heapPtr = UnsafeRawPointer(bitPattern: ptr7.load(as: UInt.self))!
// 將這個堆空間指針轉換類型後就可以很方便得訪問屬性
let hba2 = unsafeBitCast(heapPtr, to: HBA.self)
print("hba2==", hba2.name)
}
- 作爲函數參數時,可變類型的指針
UnsafeMutablePointer
和UnsafeRawPointer
與inout參數效果類似,都可以修改指向的值,不同之處在於inout參數可以直接改。
func testPointer() {
useinout(&age)
usePointer1(&age)
usePointer2(&age)
usePointer3(&age)
usePointer4(&age)
}
func useinout(_ ptr: inout Int) {
print("inout-ptr前:\(ptr)")
ptr = 90
print("inout-ptr後:\(ptr)")
}
// UnsafePointer不可修改指向內存
func usePointer1(_ ptr: UnsafePointer<Int>) { // 相當於const int *
print("ptr.pointee:\(ptr.pointee)")
}
// UnsafeMutablePointer可修改指向內容
func usePointer2(_ ptr: UnsafeMutablePointer<Int>) {// 相當於int *
print("ptr.pointee前\(ptr.pointee)")
ptr.pointee = 20
print("ptr.pointee後\(ptr.pointee)")
}
// 不可修改的原始指針
func usePointer3(_ rawptr: UnsafeRawPointer) { // 相當於const void *
print("rawptr:\(rawptr.load(as: Int.self))")
}
// UnsafeMutableRawPointer可修改指向內容的原始指針
func usePointer4(_ rawptr: UnsafeMutableRawPointer) {// 相當於void *
print("rawptr.pointee前\(rawptr.load(as: Int.self))")
rawptr.storeBytes(of: 19, as: Int.self)
print("rawptr.pointee後\(rawptr.load(as: Int.self))") // 19
}
二、創建新的指針
可通過4種方式創建新的指針:
-
UnsafeRawPointer(bitPattern: 內存地址)
、 malloc(字節數)
- 可變原始指針,
UnsafeMutableRawPointer.allocate(byteCount:字節數, alignment: 1)
- 可變指針,
UnsafeMutablePointer<泛型類型>.allocate(capacity: 泛型類型個數)
// 新創建指針
func testNewPointer() {
// 1.直接傳內存地址來創建一個原始指針
var ptr = UnsafeRawPointer(bitPattern: 0x100001234)
// 2.通過malloc來創建一個可變原始指針(可以存值)
var ptr2 = malloc(16)
// 修改
ptr2?.storeBytes(of: 118, as: Int.self)
ptr2?.storeBytes(of: 220, toByteOffset: 8, as: Int.self)
// 讀取
print((ptr2?.load(as: Int.self))!) // 118
print((ptr2?.load(fromByteOffset: 8, as: Int.self))!) //220
// 3.通過可變原始指針分配、修改、讀取內存
var ptr3 = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr3.storeBytes(of: 30, as: Int.self)
ptr3.advanced(by: 8).storeBytes(of: 33, as: Int.self)
print(ptr3.load(as: Int.self)) // 30
print(ptr3.advanced(by: 8).load(as: Int.self)) //33
// 4.通過可變指針分配、修改、讀取內存
var ptr4 = UnsafeMutablePointer<Int>.allocate(capacity: 3)
ptr4.initialize(to: 11)
ptr4.successor().initialize(to: 22)
ptr4.successor().successor().initialize(to: 33)
print("第1個int = \(ptr4.pointee), 第2個int = \((ptr4 + 1).pointee), 第3個int = \((ptr4 + 2).pointee)")
print("第1個int = \(ptr4[0]), 第2個int = \(ptr4[1]), 第3個int = \(ptr4[2])")
ptr4.deinitialize(count: 3)
ptr4.deallocate()
}
三、指針類型轉換
上述指針類型之間可以進行轉換,如下:
// 指針之間的轉換
func testPointerTransfer() {
let ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
// 1. 通過assumingMemoryBound來轉換
ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22
// 2.通過unsafeBitCast進行忽略類型的強制轉換
// 轉換爲UnsafePointer<Int>類型後通過pointee訪問
let ptr_trannsfer = unsafeBitCast(ptr, to: UnsafePointer<Int>.self)
print(ptr_trannsfer.pointee)
let ptr_trannsfer2 = unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self)
print(ptr_trannsfer2.pointee)
// 3.UnsafeMutableRawPointer可以通過bindMemory方法轉換爲UnsafeMutablePointer
let ptr222 = (ptr + 8).bindMemory(to: Double.self, capacity: 1)
ptr222.pointee = 33.0
print(ptr222.pointee)
ptr.deallocate()
}