我正在参加「启航方案」
本文主要是对指针的认识,包含指针的根本运用,以及指针的内存绑定进行详细分析
主要内容:
- 指针的认识
- 指针的常见绑定
1. 指针的认识
指针分为两类,指定数据类型和未指定数据类型
差异:
1.1 指定类型指针
代码:
运行成果:
阐明:
- 指针的内存需求自己办理,需求手动开辟空间和开释空间
- 存储数据时,需求移动必定的字节巨细
- 移动经过advanced实现
- 存储数据经过storeBytes实现
- 取出数据经过load实现
1.2 未指定类型指针
代码:
<!--界说-->
@inlinablepublicfuncwithUnsafePointer<T,Result>(tovalue:inoutT,_body:(UnsafePointer<T>)throws->Result)rethrows->Result
<!--运用1-->
varage=10
letp=withUnsafePointer(to:&age){$0}
print(p)
<!--运用2-->
withUnsafePointer(to:&age){print($0)}
<!--运用3-->
//其间p1的类型是UnsafePointer<Int>
letp1=withUnsafePointer(to:&age){ptrin
returnptr
}
阐明:
- 关于withUnsafePointer的界说,咱们能够看到闭包中回来的成果便是这个函数回来的成果
- 因而咱们在运用这个指针时,就能够经过闭包回来数据来决定拿到的成果
- 所以能够看到咱们能够有两种方法,1)直接回来指针;2)回来详细的数据
拜访特点:
直接修改:
直接在闭包中核算后将成果回来给特点
varage=10
age=withUnsafePointer(to:&age){ptrin
//回来Int整型值
returnptr.pointee+12
}
print(age)
直接修改:
varage=10
//分配容量巨细,为8字节
letptr=UnsafeMutablePointer<Int>.allocate(capacity:1)
//初始化
ptr.initialize(to:age)
ptr.deinitialize(count:1)
ptr.pointee+=12
print(ptr.pointee)
//开释
ptr.deallocate()
阐明:
- 回来指针,指针拿到pointee来进行修改
1.3 拜访结构体实例目标
结构体:
structCJLTeacher{
varage=10
varheight=1.85
}
vart=CJLTeacher()
指针处理:
//分配两个CJLTeacher巨细的空间
letptr=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)
将指针指向某个内存空间,也便是绑定到这个内存空间上
界说:
structHeapObject{
varkind:Int
varstrongRef:UInt32
varunownedRef:UInt32
}
classCJLTeacher{
varage=18
}
vart=CJLTeacher()
绑定:
//将t绑定到结构体内存中
//1、获取实例变量的内存地址,声明成了非保管目标
/*
经过Unmanaged指定内存办理,类似于OC与CF的交互方法(所有权的转化__bridge)
-passUnretained不添加引证计数,即不需求获取所有权
-passRetained添加引证计数,即需求获取所有权
-toOpaque不透明的指针
*/
letptr=Unmanaged.passUnretained(tasAnyObject).toOpaque()
//2、绑定到结构体内存,回来值是UnsafeMutablePointer<T>
/*
-bindMemory更改当时UnsafeMutableRawPointer的指针类型,绑定到详细的类型值
-假如没有绑定,则绑定
-假如现已绑定,则重定向到HeapObject类型上
*/
letheapObject=ptr.bindMemory(to:HeapObject.self,capacity:1)
//3、拜访成员变量
print(heapObject.pointee.kind)
print(heapObject.pointee.strongRef)
print(heapObject.pointee.unownedRef)
阐明:
- 首要创立一个指针,指针指向CJLTeacher
- 经过bindMemeory将指针绑定到结构体HeapObject中
- 接下来就能够经过这个指针来拜访内存数据了
2.1 元组指针类型转化(假定内存绑定assumingMemoryBound)
元组和指针指向内存的数据类型不一样,就需求运用假定内存绑定
代码:
vartul=(10,20)
//UnsafePointer<T>
functestPointer(_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)来指向
- 这是由于假定内存绑定是假绑定,不需求进行严厉的类型查看
举例:获取结构体的特点的指针
structHeapObject{
varstrongRef:UInt32=10
varunownedRef:UInt32=20
}
functestPointer(_p:UnsafePointer<Int>){
print(p)
}
//实例化
vart=HeapObject()
//获取结构体特点的指针传入函数
withUnsafePointer(to:&t){(ptr:UnsafePointer<HeapObject>)in
//1. 获取变量
letstrongRef=UnsafeRawPointer(ptr)+MemoryLayout<HeapObject>.offset(of:\HeapObject.strongRef)!
//2. 传递strongRef特点的值
testPointer(strongRef.assumingMemoryBound(to:Int.self))
}
阐明:
- 经过地址偏移拿到结构体中的strngRef变量
- 之后也是经过假定绑定将其转化为一个指针(从Uint32到Int)
2.1 经过 withMemoryRebound 暂时绑定内存类型
问题:
代码实现:
varage=10
functestPointer(_p:UnsafePointer<Int64>){
print(p)
}
letptr=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: 暂时更改内存绑定类型