指针分类:
- raw pointer:未指定数据类型的指针(原生指针)
- typed pointer:指定数据类型的指针
表明办法:
raw pointer 在swift中的表明是UnsafeRawPointer
typed pointer在swift中的表明是UnsafePointer,是一个泛型
Swift对照Objective-C,指针对应的关系:
Swift | Objective-C | 阐明 |
---|---|---|
UnsafePointer | const T * | 指针和指向的内容都是不可变的 |
UnsafeMutablePointer | 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里边的类型和办法,在当时编译进程傍边,减少编译时的内存担负
创立类型指针:
办法一:
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 }
创立泛型指针:
struct FFHobbyGirls {
var age = 10
var height = 1.85
}
var t = FFHobbyGirls()
let ptr = UnsafeMutablePointer<FFHobbyGirls>.allocate(capacity: 2)
ptr.initialize(to: FFHobbyGirls())
ptr.advanced(by: 1).initialize(to: FFHobbyGirls(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()
打印成果:
FFHobbyGirls(age: 10, height: 1.85)
FFHobbyGirls(age: 20, height: 1.75)
FFHobbyGirls(age: 10, height: 1.85)
FFHobbyGirls(age: 20, height: 1.75)
FFHobbyGirls(age: 20, height: 1.75)
Program ended with exit code: 0
知识弥补:successor()
print(ptr.successor().pointee) 与 print((ptr + 1).pointee) 成果是一致的,本质上successor()这个办法便是向前移动8字节
实战一:将将变量t绑定到结构图HeapObject内存中
思路:
代码完成:
struct HeapObject {
var kind: UnsafeRawPointer
var strongRef: UInt32
var unownedRef: UInt32
}
class FFHobbyGirls {
var age = 18
}
var t = FFHobbyGirls()
//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(引证计数+1,获取指针)
passUnretained(引证计数不+1,只获取指针)
2、bindMemory:指针重定向
实战二:将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 FFHobbyGirls {
var age = 18
}
var t = FFHobbyGirls()
//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)
依照打印出来的成果来看,显现了具体内存地址的大小,与给定的数据类型相同
扩展:xx类指针怎样转换成元类指针,运用bindMemory,原理同上
实战三:assumingMemoryBound的运用:如果将元组tuple数据传递给testPointer办法
思路:
将tuple类型转换成UnsafePointer,然后运用assumingMemoryBound假定内存绑定,告知编译器不要再次进行类型查看了
代码:
var tuple = (10, 20)
func testPointer(_ p: UnsafePointer<Int>) {
print(p)
print("end")
}
//assumingMemoryBound:假定内存绑定,告知编译器tulPtr已经绑定过Int类型了,现在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)
依据格局化输出内存地址显现,tuple已经打印出来了,0xa是10,0x14是20
实战四: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)
依据格局或内存地址的成果阐明:strongRef = 0xa =10,unownedRef = 0x14 = 20