指針分類:
- raw pointer:未指定數(shù)據(jù)類型的指針(原生指針)
- typed pointer:指定數(shù)據(jù)類型的指針
表示方式:
raw pointer 在swift中的表示是UnsafeRawPointer
typed pointer在swift中的表示是UnsafePointer<T>大莫,是一個泛型
Swift對照Objective-C,指針對應的關系:
Swift | Objective-C | 說明 |
---|---|---|
UnsafePointer<T> | const T * | 指針和指向的內容都是不可變的 |
UnsafeMutablePointer<T> | T * | 指針和指向的內容均是可變的 |
UnsafeRawPointer | const void * | 指針指向未知的類型 |
UnsafeMutableRawPointer | void * | 指針指向尾椎的類型(可以修改) |
原生指針的使用(RawPointer):
//指針內存需要手動管理
let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
for i in 0..<4 {
//advanced:步長
//storebytes:寫入內存
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()
打印結果:
index0,value:0
index1,value:1
index2,value:2
index3,value:3
Program ended with exit code: 0
內容補充:在看Swift源碼中查看UnsafeMutableRawPointer的過程中會有builtin
//builtin(標準模塊) -->在編譯的過程中會匹配LLVM里面的類型和方法冗懦,在當前編譯過程當中,減少編譯時的內存負擔
創(chuàng)建類型指針:
方式一:
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()
知識補充:單一表達式
例子:
//ptr in return ptr :單一表達式诱篷,可以直接使用ptr來表示褥民,也可以直接使用$0來表示
//方式一:
{ 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()
打印結果:
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
知識補充:successor()
print(ptr.successor().pointee) 與 print((ptr + 1).pointee) 結果是一致的斗塘,本質上successor()這個方法就是向前移動8字節(jié)
實戰(zhàn)一:將將變量t綁定到結構圖HeapObject內存中
思路:
1雾鬼、獲取實例變量的內存地址(指針)
2葱轩、RawPointer-->重新綁定到heapObject內存指針
代碼實現(xiàn):
struct HeapObject {
var kind: UnsafeRawPointer
var strongRef: UInt32
var unownedRef: UInt32
}
class LGTeacher {
var age = 18
}
var t = LGTeacher()
//1、獲取實例變量的內存地址(指針)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
//2狠毯、RawPointer-->重新綁定到heapObject內存指針
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)
print(heapObject.pointee)
輸出結果:
HeapObject(kind: 0x0000000100008168, strongRef: 3, unownedRef: 0)
Program ended with exit code: 0
知識補充:
1护糖、Unmanaged:所有權的轉換
提供兩個方法:
passRetained(引用計數(shù)+1,獲取指針)
passUnretained(引用計數(shù)不+1嚼松,只獲取指針)
2嫡良、bindMemory:指針重定向
實戰(zhàn)二:將HeapObject中kind變量綁定到lg_swift_class
思路:
1、獲取實例變量的內存地址(指針)
2献酗、將指針重新綁定到lg_swift_class類內存指針
代碼:
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寝受、獲取實例變量的內存地址(指針)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
//2、RawPointer-->重新綁定到lg_swift_class內存指針
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)
輸出結果:
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
說明:
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)
按照打印出來的結果來看罕偎,顯示了具體內存地址的大小很澄,與給定的數(shù)據(jù)類型相同
擴展:xx類指針怎么轉換成元類指針,使用bindMemory颜及,原理同上
實戰(zhàn)三:assumingMemoryBound的使用:如果將元組tuple數(shù)據(jù)傳遞給testPointer方法
思路:
將tuple類型轉換成UnsafePointer,然后使用assumingMemoryBound假定內存綁定甩苛,告訴編譯器不要再次進行類型檢查了
代碼:
var tuple = (10, 20)
func testPointer(_ p: UnsafePointer<Int>) {
print(p)
print("end")
}
//assumingMemoryBound:假定內存綁定,告訴編譯器tulPtr已經綁定過Int類型了俏站,現(xiàn)在tulptr就是Int類型讯蒲,不需要再次進行編譯檢查了
withUnsafePointer(to: &tuple) { (tulPtr: UnsafePointer<(Int, Int)>) in
testPointer(UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self))
}
輸出結果:
0x0000000100008058
(lldb) x/8g 0x0000000100008058
0x100008058: 0x000000000000000a 0x0000000000000014
0x100008068: 0x0000000000000000 0x0000000000000000
0x100008078: 0x0000000000000000 0x0000000000000000
0x100008088: 0x0000000000000000 0x0000000000000000
(lldb)
根據(jù)格式化輸出內存地址顯示,tuple已經打印出來了肄扎,0xa是10墨林,0x14是20
實戰(zhàn)四:assumingMemoryBound的使用:如何獲取結構體類型的指針
思路:
通過原生指針+偏移量的方式
代碼:
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
//通過原生指針+內存偏移來獲取
let strongRefPtr = UnsafeRawPointer(ptr) + MemoryLayout<HeapObject>.offset(of: \HeapObject.strongRef)!
testPointer(strongRefPtr.assumingMemoryBound(to: Int.self))
}
打印結果:
0x0000000100008078
(lldb) x/8g 0x0000000100008078
0x100008078: 0x000000000000000a 0x0000000000000014
0x100008088: 0x0000000100760680 0x0000000000000000
0x100008098: 0x0000000000000000 0x0000000000000000
0x1000080a8: 0x0000000000000000 0x0000000000000000
(lldb)
根據(jù)格式或內存地址的結果說明:strongRef = 0xa =10,unownedRef = 0x14 = 20
總結:學習過程中一點積累反浓,越來越好萌丈,加油