Swift?指針底層探索分析
概要
主要內(nèi)容:
指針的認(rèn)識(shí)
指針的常見(jiàn)綁定
1. 指針的認(rèn)識(shí)
指針?lè)譃閮深悾付〝?shù)據(jù)類型和未指定數(shù)據(jù)類型
區(qū)別:
1.1 指定類型指針
代碼:
運(yùn)行結(jié)果:
說(shuō)明:
- 指針的內(nèi)存需要自己管理,需要手動(dòng)開(kāi)辟空間和釋放空間
- 存儲(chǔ)數(shù)據(jù)時(shí),需要移動(dòng)一定的字節(jié)大小
- 移動(dòng)通過(guò)advanced實(shí)現(xiàn)
- 存儲(chǔ)數(shù)據(jù)通過(guò)storeBytes實(shí)現(xiàn)
- 取出數(shù)據(jù)通過(guò)load實(shí)現(xiàn)
1.2 未指定類型指針
代碼:
<!--定義--> @inlinable public func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result <!--使用1--> var age = 10 let p = withUnsafePointer(to: &age) { $0 } print(p) <!--使用2--> withUnsafePointer(to: &age){print($0)} <!--使用3--> //其中p1的類型是 UnsafePointer<Int> let p1 = withUnsafePointer(to: &age) { ptr in return ptr }
說(shuō)明:
- 對(duì)于withUnsafePointer的定義,我們可以看到閉包中返回的結(jié)果就是這個(gè)函數(shù)返回的結(jié)果
- 因此我們?cè)谑褂眠@個(gè)指針時(shí),就可以通過(guò)閉包返回?cái)?shù)據(jù)來(lái)決定拿到的結(jié)果
- 所以可以看到我們可以有兩種方式,1)直接返回指針;2)返回具體的數(shù)據(jù)
訪問(wèn)屬性:
直接修改:
直接在閉包中計(jì)算后將結(jié)果返回給屬性
var age = 10 age = withUnsafePointer(to: &age) { ptr in //返回Int整型值 return ptr.pointee + 12 } print(age)
間接修改:
var age = 10 //分配容量大小,為8字節(jié) let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1) //初始化 ptr.initialize(to: age) ptr.deinitialize(count: 1) ptr.pointee += 12 print(ptr.pointee) //釋放 ptr.deallocate()
說(shuō)明:
- 返回指針,指針拿到pointee來(lái)進(jìn)行修改
1.3 訪問(wèn)結(jié)構(gòu)體實(shí)例對(duì)象
結(jié)構(gòu)體:
struct CJLTeacher { var age = 10 var height = 1.85 } var t = CJLTeacher()
指針處理:
//分配兩個(gè)CJLTeacher大小的空間 let ptr = UnsafeMutablePointer<CJLTeacher>.allocate(capacity: 2) //初始化第一個(gè)空間 ptr.initialize(to: CJLTeacher()) //移動(dòng),初始化第2個(gè)空間 ptr.successor().initialize(to: CJLTeacher(age: 20, height: 1.75)) //訪問(wèn)方式一 print(ptr[0]) print(ptr[1]) //訪問(wèn)方式二 print(ptr.pointee) print((ptr+1).pointee) //訪問(wèn)方式三 print(ptr.pointee) //successor 往前移動(dòng) print(ptr.successor().pointee) //必須和分配是一致的 ptr.deinitialize(count: 2) //釋放 ptr.deallocate()
說(shuō)明:
- 直接通過(guò)下標(biāo)來(lái)獲取
- 通過(guò)指針偏移來(lái)獲取
- 通過(guò)successor()偏移一步來(lái)獲取,它可以通用在指定指針類型和未指定指針類型
2. 指針的常見(jiàn)綁定
2.1 指針與內(nèi)存空間的綁定(指向)(bindMemory)
將指針指向某個(gè)內(nèi)存空間,也就是綁定到這個(gè)內(nèi)存空間上
定義:
struct HeapObject { var kind: Int var strongRef: UInt32 var unownedRef: UInt32 } class CJLTeacher{ var age = 18 } var t = CJLTeacher()
綁定:
//將t綁定到結(jié)構(gòu)體內(nèi)存中 //1、獲取實(shí)例變量的內(nèi)存地址,聲明成了非托管對(duì)象 /* 通過(guò)Unmanaged指定內(nèi)存管理,類似于OC與CF的交互方式(所有權(quán)的轉(zhuǎn)換 __bridge) - passUnretained 不增加引用計(jì)數(shù),即不需要獲取所有權(quán) - passRetained 增加引用計(jì)數(shù),即需要獲取所有權(quán) - toOpaque 不透明的指針 */ let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque() //2、綁定到結(jié)構(gòu)體內(nèi)存,返回值是UnsafeMutablePointer<T> /* - bindMemory 更改當(dāng)前 UnsafeMutableRawPointer 的指針類型,綁定到具體的類型值 - 如果沒(méi)有綁定,則綁定 - 如果已經(jīng)綁定,則重定向到 HeapObject類型上 */ let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1) //3、訪問(wèn)成員變量 print(heapObject.pointee.kind) print(heapObject.pointee.strongRef) print(heapObject.pointee.unownedRef)
說(shuō)明:
- 首先創(chuàng)建一個(gè)指針,指針指向CJLTeacher
- 通過(guò)bindMemeory將指針綁定到結(jié)構(gòu)體HeapObject中
- 接下來(lái)就可以通過(guò)這個(gè)指針來(lái)訪問(wèn)內(nèi)存數(shù)據(jù)了
2.2 元組指針類型轉(zhuǎn)換(假定內(nèi)存綁定assumingMemoryBound)
元組和指針指向內(nèi)存的數(shù)據(jù)類型不一樣,就需要使用假定內(nèi)存綁定
代碼:
var tul = (10, 20) //UnsafePointer<T> func testPointer(_ p : UnsafePointer<Int>){ print(p) } withUnsafePointer(to: &tul) { (tulPtr: UnsafePointer<(Int, Int)>) in //不能使用bindMemory,因?yàn)橐呀?jīng)綁定到具體的內(nèi)存中了 //使用assumingMemoryBound,假定內(nèi)存綁定,目的是告訴編譯器ptr已經(jīng)綁定過(guò)Int類型了,不需要再檢查memory綁定 testPointer(UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self)) }
說(shuō)明:
- testPointe需要傳入的是一個(gè)泛型為Int的指針
- 我們此時(shí)想要傳入一個(gè)元組,元組類型為(Int, Int),與Int類型不一樣
- 因此無(wú)法通過(guò)memoryBind來(lái)直接指向Int內(nèi)存
- 所以就需要通過(guò)assumingMemoryBound(to: Int.self)來(lái)指向
- 這是因?yàn)榧俣▋?nèi)存綁定是假綁定,不需要進(jìn)行嚴(yán)格的類型檢查
舉例:獲取結(jié)構(gòu)體的屬性的指針
struct HeapObject { var strongRef: UInt32 = 10 var unownedRef: UInt32 = 20 } func testPointer(_ p: UnsafePointer<Int>){ print(p) } //實(shí)例化 var t = HeapObject() //獲取結(jié)構(gòu)體屬性的指針傳入函數(shù) withUnsafePointer(to: &t) { (ptr: UnsafePointer<HeapObject>) in //1. 獲取變量 let strongRef = UnsafeRawPointer(ptr) + MemoryLayout<HeapObject>.offset(of: \HeapObject.strongRef)! //2. 傳遞strongRef屬性的值 testPointer(strongRef.assumingMemoryBound(to: Int.self)) }
說(shuō)明:
- 通過(guò)地址偏移拿到結(jié)構(gòu)體中的strngRef變量
- 之后也是通過(guò)假定綁定將其轉(zhuǎn)換為一個(gè)指針(從Uint32到Int)
2.3 通過(guò) withMemoryRebound 臨時(shí)綁定內(nèi)存類型
問(wèn)題:
代碼實(shí)現(xiàn):
var age = 10 func testPointer(_ p: UnsafePointer<Int64>){ print(p) } let ptr = withUnsafePointer(to: &age) {$0} ptr.withMemoryRebound(to: Int64.self, capacity: 1) { (ptr: UnsafePointer<Int64>) in testPointer(ptr) }
說(shuō)明:
- 此處可以看到ptr的指針?lè)盒蜑镮nt,而testPointer的參數(shù)指針?lè)盒蜑镮nt64,所以并不能直接傳遞
- 而這個(gè)指針我們只是作為參數(shù)傳遞,所以就可以臨時(shí)綁定一下
- 實(shí)現(xiàn)方式就是ptr.withMemoryRebound(to: Int64.self, capacity: 1)
- 在出了這個(gè)作用域后,ptr仍然是Int類型
3、總結(jié)
- 指針類型分兩種
- typed pointer 指定數(shù)據(jù)類型指針,即 UnsafePointer< T > + unsafeMutablePointer
- raw pointer 未指定數(shù)據(jù)類型的指針(原生指針) ,即UnsafeRawPointer + unsafeMutableRawPointer
指針的內(nèi)存管理需要手動(dòng)管理
假定內(nèi)存綁定和內(nèi)存綁定的區(qū)別
需要注意對(duì)于指針類型指針,可以通過(guò)指針偏移來(lái)偏移內(nèi)存大小,而對(duì)于未指定類型的指針,只能通過(guò)內(nèi)存偏移來(lái)偏移內(nèi)存大小
將一個(gè)指針綁定到內(nèi)存中,其實(shí)就是指向到這個(gè)內(nèi)存空間
三種綁定的區(qū)別
- 綁定:bindMemory(to: Capacity:): 更改內(nèi)存綁定的類型,如果之前沒(méi)有綁定,那么就是首次綁定,如果綁定過(guò)了,會(huì)被重新綁定為該類型
- 假定綁定:assumingMemoryBound假定內(nèi)存綁定,這里就是告訴編譯器:我的類型就是這個(gè),你不要檢查我了,其實(shí)際類型還是原來(lái)的類型
- 臨時(shí)綁定:withMemoryRebound: 臨時(shí)更改內(nèi)存綁定類型
以上就是Swift 指針底層探索分析的詳細(xì)內(nèi)容,更多關(guān)于Swift 指針底層的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Swift中的類class與結(jié)構(gòu)體struct體學(xué)習(xí)筆記
和C++一樣,Swfit中同時(shí)擁有類與結(jié)構(gòu)體,能夠充分滿足開(kāi)發(fā)者面向?qū)ο蠛兔嫦蜻^(guò)程編程的需求,這里我們就來(lái)看一下Swift中的類class與結(jié)構(gòu)體struct體學(xué)習(xí)筆記2016-07-07Swift3.0剪切板代碼拷貝及跨應(yīng)用粘貼實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Swift3.0剪切板代碼拷貝及跨應(yīng)用粘貼的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法
這篇文章主要介紹了iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03