網站首頁 編程語言 正文
概要
主要內容:
指針的認識
指針的常見綁定
1. 指針的認識
指針分為兩類,指定數據類型和未指定數據類型
區別:
1.1 指定類型指針
代碼:
運行結果:
說明:
- 指針的內存需要自己管理,需要手動開辟空間和釋放空間
- 存儲數據時,需要移動一定的字節大小
- 移動通過advanced實現
- 存儲數據通過storeBytes實現
- 取出數據通過load實現
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
}
說明:
- 對于withUnsafePointer的定義,我們可以看到閉包中返回的結果就是這個函數返回的結果
- 因此我們在使用這個指針時,就可以通過閉包返回數據來決定拿到的結果
- 所以可以看到我們可以有兩種方式,1)直接返回指針;2)返回具體的數據
訪問屬性:
直接修改:
直接在閉包中計算后將結果返回給屬性
var age = 10
age = withUnsafePointer(to: &age) { ptr in
//返回Int整型值
return ptr.pointee + 12
}
print(age)
間接修改:
var age = 10
//分配容量大小,為8字節
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
//初始化
ptr.initialize(to: age)
ptr.deinitialize(count: 1)
ptr.pointee += 12
print(ptr.pointee)
//釋放
ptr.deallocate()
說明:
- 返回指針,指針拿到pointee來進行修改
1.3 訪問結構體實例對象
結構體:
struct CJLTeacher {
var age = 10
var height = 1.85
}
var t = CJLTeacher()
指針處理:
//分配兩個CJLTeacher大小的空間
let ptr = UnsafeMutablePointer<CJLTeacher>.allocate(capacity: 2)
//初始化第一個空間
ptr.initialize(to: CJLTeacher())
//移動,初始化第2個空間
ptr.successor().initialize(to: CJLTeacher(age: 20, height: 1.75))
//訪問方式一
print(ptr[0])
print(ptr[1])
//訪問方式二
print(ptr.pointee)
print((ptr+1).pointee)
//訪問方式三
print(ptr.pointee)
//successor 往前移動
print(ptr.successor().pointee)
//必須和分配是一致的
ptr.deinitialize(count: 2)
//釋放
ptr.deallocate()
說明:
- 直接通過下標來獲取
- 通過指針偏移來獲取
- 通過successor()偏移一步來獲取,它可以通用在指定指針類型和未指定指針類型
2. 指針的常見綁定
2.1 指針與內存空間的綁定(指向)(bindMemory)
將指針指向某個內存空間,也就是綁定到這個內存空間上
定義:
struct HeapObject {
var kind: Int
var strongRef: UInt32
var unownedRef: UInt32
}
class CJLTeacher{
var age = 18
}
var t = CJLTeacher()
綁定:
//將t綁定到結構體內存中
//1、獲取實例變量的內存地址,聲明成了非托管對象
/*
通過Unmanaged指定內存管理,類似于OC與CF的交互方式(所有權的轉換 __bridge)
- passUnretained 不增加引用計數,即不需要獲取所有權
- passRetained 增加引用計數,即需要獲取所有權
- toOpaque 不透明的指針
*/
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
//2、綁定到結構體內存,返回值是UnsafeMutablePointer<T>
/*
- bindMemory 更改當前 UnsafeMutableRawPointer 的指針類型,綁定到具體的類型值
- 如果沒有綁定,則綁定
- 如果已經綁定,則重定向到 HeapObject類型上
*/
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)
//3、訪問成員變量
print(heapObject.pointee.kind)
print(heapObject.pointee.strongRef)
print(heapObject.pointee.unownedRef)
說明:
- 首先創建一個指針,指針指向CJLTeacher
- 通過bindMemeory將指針綁定到結構體HeapObject中
- 接下來就可以通過這個指針來訪問內存數據了
2.2 元組指針類型轉換(假定內存綁定assumingMemoryBound)
元組和指針指向內存的數據類型不一樣,就需要使用假定內存綁定
代碼:
var tul = (10, 20)
//UnsafePointer<T>
func testPointer(_ p : UnsafePointer<Int>){
print(p)
}
withUnsafePointer(to: &tul) { (tulPtr: UnsafePointer<(Int, Int)>) in
//不能使用bindMemory,因為已經綁定到具體的內存中了
//使用assumingMemoryBound,假定內存綁定,目的是告訴編譯器ptr已經綁定過Int類型了,不需要再檢查memory綁定
testPointer(UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self))
}
說明:
- testPointe需要傳入的是一個泛型為Int的指針
- 我們此時想要傳入一個元組,元組類型為(Int, Int),與Int類型不一樣
- 因此無法通過memoryBind來直接指向Int內存
- 所以就需要通過assumingMemoryBound(to: Int.self)來指向
- 這是因為假定內存綁定是假綁定,不需要進行嚴格的類型檢查
舉例:獲取結構體的屬性的指針
struct HeapObject {
var strongRef: UInt32 = 10
var unownedRef: UInt32 = 20
}
func testPointer(_ p: UnsafePointer<Int>){
print(p)
}
//實例化
var t = HeapObject()
//獲取結構體屬性的指針傳入函數
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))
}
說明:
- 通過地址偏移拿到結構體中的strngRef變量
- 之后也是通過假定綁定將其轉換為一個指針(從Uint32到Int)
2.3 通過 withMemoryRebound 臨時綁定內存類型
問題:
代碼實現:
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)
}
說明:
- 此處可以看到ptr的指針泛型為Int,而testPointer的參數指針泛型為Int64,所以并不能直接傳遞
- 而這個指針我們只是作為參數傳遞,所以就可以臨時綁定一下
- 實現方式就是ptr.withMemoryRebound(to: Int64.self, capacity: 1)
- 在出了這個作用域后,ptr仍然是Int類型
3、總結
- 指針類型分兩種
- typed pointer 指定數據類型指針,即 UnsafePointer< T > + unsafeMutablePointer
- raw pointer 未指定數據類型的指針(原生指針) ,即UnsafeRawPointer + unsafeMutableRawPointer
指針的內存管理需要手動管理
假定內存綁定和內存綁定的區別
需要注意對于指針類型指針,可以通過指針偏移來偏移內存大小,而對于未指定類型的指針,只能通過內存偏移來偏移內存大小
將一個指針綁定到內存中,其實就是指向到這個內存空間
三種綁定的區別
- 綁定:bindMemory(to: Capacity:): 更改內存綁定的類型,如果之前沒有綁定,那么就是首次綁定,如果綁定過了,會被重新綁定為該類型
- 假定綁定:assumingMemoryBound假定內存綁定,這里就是告訴編譯器:我的類型就是這個,你不要檢查我了,其實際類型還是原來的類型
- 臨時綁定:withMemoryRebound: 臨時更改內存綁定類型
原文鏈接:https://juejin.cn/post/7146419541059305502
相關推薦
- 2022-09-13 iOS封裝倒計時按鈕HLCountDownButton示例詳解_IOS
- 2021-11-16 linux系統下用戶管理相關介紹_Linux
- 2022-06-19 Visual?Studio創建WPF項目_實用技巧
- 2023-08-16 uniapp中v-model數據無法讀取問題 failed for prop “value“
- 2022-08-31 C++淺析構造函數的特性_C 語言
- 2022-05-27 Flutter組件狀態管理的3種方法_Android
- 2022-09-12 PyQt轉換路徑中的斜杠(斜杠(/)與反斜杠(\)轉換)_python
- 2022-10-23 使用React組件編寫溫度顯示器_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支