Swift指針

指針?lè)诸?lèi):

  • raw pointer:未指定數(shù)據(jù)類(lèi)型的指針(原生指針)
  • typed pointer:指定數(shù)據(jù)類(lèi)型的指針

表示方式:

raw pointer 在swift中的表示是UnsafeRawPointer

typed pointer在swift中的表示是UnsafePointer<T>,是一個(gè)泛型

Swift對(duì)照Objective-C,指針對(duì)應(yīng)的關(guān)系:

Swift Objective-C 說(shuō)明
UnsafePointer<T> const T * 指針和指向的內(nèi)容都是不可變的
UnsafeMutablePointer<T> T * 指針和指向的內(nèi)容均是可變的
UnsafeRawPointer const void * 指針指向未知的類(lèi)型
UnsafeMutableRawPointer void * 指針指向尾椎的類(lèi)型(可以修改)
原生指針的使用(RawPointer):
//指針內(nèi)存需要手動(dòng)管理

let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)

for i in 0..<4 {
    //advanced:步長(zhǎng)
    //storebytes:寫(xiě)入內(nèi)存
    p.advanced(by: i * 8).storeBytes(of: i, as: Int.self)
}

for i in 0..<4 {
    let value = p.load(fromByteOffset: i * 8, as: Int.self)
    print("index\(i),value:\(value)")
}

p.deallocate()

打印結(jié)果:

index0,value:0
index1,value:1
index2,value:2
index3,value:3
Program ended with exit code: 0

內(nèi)容補(bǔ)充:在看Swift源碼中查看UnsafeMutableRawPointer的過(guò)程中會(huì)有builtin

//builtin(標(biāo)準(zhǔn)模塊) -->在編譯的過(guò)程中會(huì)匹配LLVM里面的類(lèi)型和方法,在當(dāng)前編譯過(guò)程當(dāng)中,減少編譯時(shí)的內(nèi)存負(fù)擔(dān)

創(chuàng)建類(lèi)型指針:
方式一:
var age = 10
let p = withUnsafePointer(to: &age) { $0 }
方式二:
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1)

ptr.initialize(to: age)

ptr.deinitialize(count: 1)

ptr.deallocate()

知識(shí)補(bǔ)充:?jiǎn)我槐磉_(dá)式
例子:

//ptr in return ptr :?jiǎn)我槐磉_(dá)式,可以直接使用ptr來(lái)表示,也可以直接使用$0來(lái)表示
//方式一:
{ ptr in return ptr }
方式二:
{ ptr }
方式三:
{ $0 }
創(chuàng)建泛型指針:
struct LGTeacher {
    var age = 10
    var height = 1.85
}

var t = LGTeacher()

let ptr = UnsafeMutablePointer<LGTeacher>.allocate(capacity: 2)

ptr.initialize(to: LGTeacher())

ptr.advanced(by: 1).initialize(to: LGTeacher(age: 20, height: 1.75))

print(ptr[0])

print(ptr[1])

print(ptr.pointee)

print((ptr + 1).pointee)

print(ptr.successor().pointee)

ptr.deinitialize(count: 2)

ptr.deallocate()

打印結(jié)果:

LGTeacher(age: 10, height: 1.85)
LGTeacher(age: 20, height: 1.75)
LGTeacher(age: 10, height: 1.85)
LGTeacher(age: 20, height: 1.75)
LGTeacher(age: 20, height: 1.75)
Program ended with exit code: 0

知識(shí)補(bǔ)充:successor()

print(ptr.successor().pointee) 與 print((ptr + 1).pointee) 結(jié)果是一致的,本質(zhì)上successor()這個(gè)方法就是向前移動(dòng)8字節(jié)

實(shí)戰(zhàn)一:將將變量t綁定到結(jié)構(gòu)圖HeapObject內(nèi)存中

思路:

1、獲取實(shí)例變量的內(nèi)存地址(指針)
2、RawPointer-->重新綁定到heapObject內(nèi)存指針

代碼實(shí)現(xiàn):

struct HeapObject {
    var kind: UnsafeRawPointer
    var strongRef: UInt32
    var unownedRef: UInt32
}

class LGTeacher {
    var age = 18
}

var t = LGTeacher()

//1、獲取實(shí)例變量的內(nèi)存地址(指針)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

//2、RawPointer-->重新綁定到heapObject內(nèi)存指針
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)

print(heapObject.pointee)

輸出結(jié)果:

HeapObject(kind: 0x0000000100008168, strongRef: 3, unownedRef: 0)
Program ended with exit code: 0

知識(shí)補(bǔ)充:

1、Unmanaged:所有權(quán)的轉(zhuǎn)換
提供兩個(gè)方法:
passRetained(引用計(jì)數(shù)+1,獲取指針)
passUnretained(引用計(jì)數(shù)不+1,只獲取指針)

2、bindMemory:指針重定向

實(shí)戰(zhàn)二:將HeapObject中kind變量綁定到lg_swift_class

思路:

1、獲取實(shí)例變量的內(nèi)存地址(指針)
2、將指針重新綁定到lg_swift_class類(lèi)內(nèi)存指針

代碼:

struct HeapObject {
    var kind: UnsafeRawPointer
    var strongRef: UInt32
    var unownedRef: UInt32
}

struct lg_swift_class {
    var kind: UnsafeRawPointer
    var superClass: UnsafeRawPointer
    var cacheData1: UnsafeRawPointer
    var cacheData2: UnsafeRawPointer
    var data: UnsafeRawPointer
    var falgs: UInt32
    var instanceAddressOffset: UInt32
    var instanceSize: UInt32
    var finstanceAlignMaskags: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressOffset: UInt32
    var description: UnsafeRawPointer
}

class LGTeacher {
    var age = 18
}

var t = LGTeacher()

//1、獲取實(shí)例變量的內(nèi)存地址(指針)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

//2、RawPointer-->重新綁定到lg_swift_class內(nèi)存指針
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)

let metaPtr = heapObject.pointee.kind.bindMemory(to: lg_swift_class.self, capacity: 1)

print(metaPtr.pointee)

輸出結(jié)果:

lg_swift_class(kind: 0x0000000100008140, superClass: 0x00007fff889888f8, cacheData1: 0x00007fff20206af0, cacheData2: 0x0000802000000000, data: 0x0000000100776562, falgs: 2, instanceAddressOffset: 0, instanceSize: 24, finstanceAlignMaskags: 7, reserved: 0, classSize: 136, classAddressOffset: 16, description: 0x0000000100003c3c)
Program ended with exit code: 0

說(shuō)明:

lg_swift_class(kind: 0x0000000100008140, superClass: 0x00007fff889888f8, cacheData1: 0x00007fff20206af0, cacheData2: 0x0000802000000000, data: 0x0000000100776562, falgs: 2, instanceAddressOffset: 0, instanceSize: 24, finstanceAlignMaskags: 7, reserved: 0, classSize: 136, classAddressOffset: 16, description: 0x0000000100003c3c)
按照打印出來(lái)的結(jié)果來(lái)看,顯示了具體內(nèi)存地址的大小,與給定的數(shù)據(jù)類(lèi)型相同

擴(kuò)展:xx類(lèi)指針怎么轉(zhuǎn)換成元類(lèi)指針,使用bindMemory,原理同上

實(shí)戰(zhàn)三:assumingMemoryBound的使用:如果將元組tuple數(shù)據(jù)傳遞給testPointer方法

思路:

將tuple類(lèi)型轉(zhuǎn)換成UnsafePointer,然后使用assumingMemoryBound假定內(nèi)存綁定,告訴編譯器不要再次進(jìn)行類(lèi)型檢查了

代碼:

var tuple = (10, 20)

func testPointer(_ p: UnsafePointer<Int>) {
    print(p)
    print("end")
}

//assumingMemoryBound:假定內(nèi)存綁定,告訴編譯器tulPtr已經(jīng)綁定過(guò)Int類(lèi)型了,現(xiàn)在tulptr就是Int類(lèi)型,不需要再次進(jìn)行編譯檢查了
withUnsafePointer(to: &tuple) { (tulPtr: UnsafePointer<(Int, Int)>) in
    testPointer(UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self))
}

輸出結(jié)果:

0x0000000100008058
(lldb) x/8g 0x0000000100008058
0x100008058: 0x000000000000000a 0x0000000000000014
0x100008068: 0x0000000000000000 0x0000000000000000
0x100008078: 0x0000000000000000 0x0000000000000000
0x100008088: 0x0000000000000000 0x0000000000000000
(lldb) 

根據(jù)格式化輸出內(nèi)存地址顯示,tuple已經(jīng)打印出來(lái)了,0xa是10,0x14是20

實(shí)戰(zhàn)四:assumingMemoryBound的使用:如何獲取結(jié)構(gòu)體類(lèi)型的指針

思路:

通過(guò)原生指針+偏移量的方式

代碼:

struct HeapObject {
    var strongRef = 10
    var unownedRef = 20
}

func testPointer(_ p: UnsafePointer<Int>) {
    print(p)
    print("end")
}

var t = HeapObject()

withUnsafePointer(to: &t) { (ptr: UnsafePointer<HeapObject>) in
    //通過(guò)原生指針+內(nèi)存偏移來(lái)獲取
    let strongRefPtr = UnsafeRawPointer(ptr) + MemoryLayout<HeapObject>.offset(of: \HeapObject.strongRef)!
    testPointer(strongRefPtr.assumingMemoryBound(to: Int.self))
}

打印結(jié)果:

0x0000000100008078
(lldb) x/8g 0x0000000100008078
0x100008078: 0x000000000000000a 0x0000000000000014
0x100008088: 0x0000000100760680 0x0000000000000000
0x100008098: 0x0000000000000000 0x0000000000000000
0x1000080a8: 0x0000000000000000 0x0000000000000000
(lldb) 

根據(jù)格式或內(nèi)存地址的結(jié)果說(shuō)明:strongRef = 0xa =10,unownedRef = 0x14 = 20

總結(jié):學(xué)習(xí)過(guò)程中一點(diǎn)積累,越來(lái)越好,加油

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift 指針 前言 指針,作為編程中最重要的概念,一直存在于各大語(yǔ)言中,下面我們就來(lái)探索一下Swift中的指針...
    just東東閱讀 992評(píng)論 0 3
  • 參考文獻(xiàn) Swift結(jié)構(gòu)體指針操作官方文檔Swift 和 C 不得不說(shuō)的故事Swift指針和托管,你看我就夠了 W...
    沉靜BBQ閱讀 8,211評(píng)論 1 25
  • 為了避免疏漏, 我從官方文檔作了截圖, 蘋(píng)果官網(wǎng)文檔1 , 文檔2 本文概要 按照官方文檔, 介紹Swift中的指...
    Lin__Chuan閱讀 2,815評(píng)論 12 9
  • 前言 本篇文章主要講解一下Swift中的指針,以及相關(guān)的應(yīng)用場(chǎng)景,指針也是面試官經(jīng)常問(wèn)到的知識(shí)點(diǎn),希望大家能夠掌握...
    深圳_你要的昵稱閱讀 3,615評(píng)論 0 11
  • 本文系學(xué)習(xí)Swift中的指針操作詳解的整理 默認(rèn)情況下Swift是內(nèi)存安全的,蘋(píng)果官方不鼓勵(lì)我們直接操作內(nèi)存。但是...
    流火緋瞳閱讀 15,317評(píng)論 2 28

友情鏈接更多精彩內(nèi)容