欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift?指針底層探索分析

 更新時(shí)間:2022年09月23日 15:05:42   作者:文乙  
這篇文章主要為大家介紹了Swift?指針底層探索分析,主要包括指針的基本使用,以及指針的內(nèi)存綁定進(jìn)行詳細(xì)分析,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

概要

主要內(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í)筆記

    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-07
  • Swift3.0剪切板代碼拷貝及跨應(yīng)用粘貼實(shí)現(xiàn)代碼

    Swift3.0剪切板代碼拷貝及跨應(yīng)用粘貼實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Swift3.0剪切板代碼拷貝及跨應(yīng)用粘貼的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 深入講解Swift中的模式匹配

    深入講解Swift中的模式匹配

    在Swift中,一些模式已經(jīng)被語(yǔ)言特性所吸收,你在使用Swift甚至察覺(jué)不出這類問(wèn)題的存在,下面這篇文章主要給大家介紹了關(guān)于Swift中模式匹配的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • Swift中的訪問(wèn)控制和protected

    Swift中的訪問(wèn)控制和protected

    這篇文章主要介紹了Swift中的訪問(wèn)控制和protected,本文主要講解為什么Swift沒(méi)有類似protected的選項(xiàng),需要的朋友可以參考下
    2015-05-05
  • iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法

    iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法

    這篇文章主要介紹了iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • Swift面試題及答案整理

    Swift面試題及答案整理

    雖然Swift出現(xiàn)的時(shí)間不久,但是它已經(jīng)成為最流行的編程語(yǔ)言之一了。Swift的知識(shí)浩如煙海,但是怎么測(cè)試你掌握了多少?通過(guò)下面這篇整理關(guān)于Swift面試題及答案,可能會(huì)對(duì)你所掌握的Swift進(jìn)行一個(gè)判斷,需要的朋友可以參考借鑒。
    2017-01-01
  • 初步理解Swift中的泛型

    初步理解Swift中的泛型

    這篇文章主要介紹了初步理解Swift中的泛型,是Swift入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-07-07
  • 10個(gè)驚艷的Swift單行代碼

    10個(gè)驚艷的Swift單行代碼

    這篇文章主要為大家分享了10個(gè)驚艷的Swift單行代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Swift中字典與JSON轉(zhuǎn)換的方法

    Swift中字典與JSON轉(zhuǎn)換的方法

    Swift中經(jīng)常會(huì)遇到字典和字符串的相互轉(zhuǎn)換,本篇文章主要介紹了Swift中字典與JSON轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Swift教程之方法詳解

    Swift教程之方法詳解

    這篇文章主要介紹了Swift教程之方法詳解,方法是關(guān)聯(lián)到一個(gè)特定類型的函數(shù),類、結(jié)構(gòu)、枚舉所有可以定義實(shí)例方法,封裝特定任務(wù)和功能處理給定類型的一個(gè)實(shí)例,需要的朋友可以參考下
    2015-01-01

最新評(píng)論