1.Swift中指针分为两类:
- Raw Pointer 未指定数据类型指针(原生指针)--> UnsafeRawPointer
- Type Pointer 指定数据类型指针 --> UnsafePointer
- 下面我们来看Swift中的指针和OC中指针的对应关系
-
Swift
Object-
C 说明
-
UnsafePointer<
T> const
T* 指针及所指向的内容都不可变
-
UnsafeMutablePointer
T * 指针及其所指向的内存内容均可变
-
UnsafeRawPointer const void * 指针指向未知类型
-
UnsafeMutableRawPointer void * 指针指向未知类型
2.原生指针的使用(UnsafeMutableRawPointer)
- 假设我们想在内存中存储连续4个整型的数据,我们如何使用Raw Pointer来实现呢?
- 原生指针的使用是需要我们对其内存进行手动管理的、在使用的时候创建、使用完毕后需要释放allocate和deallocate成对出现。
- 分配指定大小的内存空间、规定对齐方式为
- advanced移动当前存储值的内存大小,storeBytes存储我们当前的数据
- load加载相对于我们当前指针首地址的偏移
-
//分配32字节大小的内存空间、对其方式为:8字节对齐
-
let p =
UnsafeMutableRawPointer.allocate(byteCount:
32, alignment:
8)
-
for i
in
0..<
4{
-
//advanced代表当前 p 前进的步长,对于RawPointer来说,我们需要移动的是当前存储值的内存大小,既MemoryLayout.stride
-
//storeBytes:这里就是存储我们当前的数据,这里需要指定当前数据的类型
-
p.advanced(by: i*
8).storeBytes(of: i+
1,
as:
Int.
self)
-
}
-
for i
in
0..<
4{
-
//load 表示加载,fromBytesOffset: 是相对于我们当前p 的首地址的偏移
-
let value = p.load(fromByteOffset: i*
8,
as:
Int.
self)
-
print(
"index\(i),value\(value)")
-
}
-
p.deallocate()
- 其中UnsafeMutableRawPointer的allocate方法底层实现为 :(在源码 swift/stdlib/public/core/UnsafeRawPointer.swift 搜索 "allocate(" )
- 匹配对齐方式
- 通过Builtin.allocRaw创建UnsafeMutableRawPointer对象
-
@inlinable
-
public
static
func allocate(
-
byteCount: Int, alignment: Int
-
) ->
UnsafeMutableRawPointer {
-
var alignment = alignment
//匹配当前对齐方式
-
if alignment <= _minAllocationAlignment() {
-
alignment =
0
-
}
//Builtin:Swift中的标准模块(本质上编译过程中会匹配LLVM中的类型和方法、在当前调用过程中减少Swift运行负担)
-
return
UnsafeMutableRawPointer(
Builtin.allocRaw(
-
byteCount._builtinWordValue, alignment._builtinWordValue))
-
}
3.范型指针的使用(UnsafePointer):确定类型的指针
- 如何获取变量的地址?
- withUnsafeMutablePointer(to: T){$0}
- 获取上述表达式的返回结果既为当前指针
- x/8g输出既得到当前变量地址
-
var age =
18
-
withUnsafeMutablePointer(to: &age){$
0}
//单一表达式:$0与return ptr表达式性质一样
-
let b =
withUnsafePointer(to: &age) { (ptr)
in
return ptr }
-
//使用pointee来访问当前指针变量值
-
print(b.pointee)
//18
- 如何通过指针改变当前变量值?
- 不可变指针间接修改变量值
-
- withUnsafePointer的返回值是 UnsafePointer,意味着我们不能直接修改值(如我们C语言中的 char *p = "HS")
- C中我们使用 *p 来访问我们的 "HS", 顾在这里我们使用 ptr.pointee来访问age的值,从而修改age值。
-
- 不可变指针间接修改变量值
-
age =
withUnsafePointer(to: &age, { (ptr)
in
-
return ptr.pointee +
12
//Int整形值 30
-
})
- 可变指针 直接修改变量值
-
- 使用withUnsafeMutablePointer来直接修改我们的变量值、返回变量的结果取决于闭包表达式中的操作
- 使用var name:String = "Holo"在闭包表达式中做ptr.pointee += "thurian" 操作会得到 name = "Holothurian"
-
withUnsafeMutablePointer(to: &age) { ptr
in
-
ptr.pointee +=
6
-
}
-
print(age)
//36
- 指定数据类型指针(Type Pointer):UnsafeMutablePointer
-
var age =
10
-
//1、capacity:容量大小,当前的大小为 1 * 8字节
-
let ptr =
UnsafeMutablePointer<
Int>.allocate(capacity:
1)
-
//2、初始化当前的UnsafeMutablePointer<Int> 指针
-
ptr.initialize(to: age)
-
age = ptr.pointee +
12
//age = 22
-
//3、下面两个成对调用,内存管理
-
ptr.deinitialize(
count:
1)
-
ptr.deallocate()
- 分析指定结构体类型指针
-
struct LGTeacher {
-
var age =
10
-
var height =
1.88
-
}
-
var t =
LGTeacher()
-
let ptt =
UnsafeMutablePointer<
LGTeacher>.allocate(capacity:
2)
-
ptt.initialize(to:
LGTeacher())
//初始化完成
-
//1、可以通过该种方式进行访问下一块内存空间
-
ptt.advanced(by:
1).initialize(to:
LGTeacher(age:
20, height:
1.88))
-
print(ptt[
0])
//LGTeacher(age: 10, height: 1.88)
-
print(ptt[
1])
//LGTeacher(age: 20, height: 1.99)
-
//2、通过访问ptt.pointee获取首地址值
-
print(ptt.pointee)
//LGTeacher(age: 10, height: 1.88)
-
print((ptt+
1).pointee)
//LGTeacher(age: 20, height: 1.99)
-
//3、通过successor访问 ;successor往前移动8字节
-
print(ptt.successor().pointee)
//LGTeacher(age: 20, height: 1.99)
-
ptt.deinitialize(
count:
2)
-
ptt.deallocate()
案例练习:将HSTeacher创建的实例变量绑定到结构体HeapObject内存中
-
struct HeapObject {
-
var kind:
UnsafeRawPointer
-
var strongref:
UInt32
-
var unownedRef:
UInt32
-
}
-
class HSTeacher{
-
var age =
19
-
}
- 首先获取到实例变量的地址
- 然后使用Unmanaged获取非托管实例对象的指针
- 最后将获取的实例变量的指针绑定到具体类型;
-
var temp =
HSTeacher()
-
//Unmanaged相当于OC 和CF交互方式中, __bridge 所有权的转换
-
//create,copy使用retained; opaque不透明
-
//passUnretained不增加引用计数、passRetained增加引用计数
-
//CFRealse //passUnretained申明非托管对象
-
let ptrrr =
Unmanaged.passUnretained(temp
as
AnyObject).toOpaque()
//不需要获得对象的所有权
-
let ptrl =
Unmanaged.passRetained(temp)
//获得对象所有权
-
print(ptrrr)
//0x000000010070d1f0
-
print(ptrl)
//Unmanaged<HSTeacher>(_value: SwiftPointer.HSTeacher)
-
//当前内存指针绑定到具体类型:返回 UnsafeMutablePointer
-
let headObject = ptrrr.bindMemory(to:
HeapObject.
self, capacity:
1)
-
let a = headObject.pointee.kind
//0x000000010000c308
-
let s = headObject.pointee.strongref
//2
-
let k = headObject.pointee.unownedRef
//2
- 如何将HeapObject中的kind绑定到我们的类的结构内存中?
- 通过类的结构分析我们得到类的结构如下:
-
struct hs_swift_class {
-
var kind:
UnsafeRawPointer
-
var superClass:
UnsafeRawPointer
-
var cachedata1:
UnsafeRawPointer
-
var cachedata2:
UnsafeRawPointer
-
var data:
UnsafeRawPointer
-
var flags:
UInt32
-
var instanceAddressOffset:
UInt32
-
var instanceSize:
UInt32
-
var flinstanceAlignMask:
UInt32
-
var reserved:
UInt16
-
var classSize:
UInt32
-
var classAddressOffset:
UInt32
-
var description:
UnsafeRawPointer
-
}
- 那么我们进行绑定如下:
- bindMemory(to: Capacity:) 更改内存绑定的类型,如果之前没有绑定,那么就是⾸次绑定;如果绑定过了,会被重新绑定为该类型。
-
var temp =
HSTeacher()
-
let ptr =
Unmanaged.passUnretained(temp
as
AnyObject).toOpaque()
-
let headObject = ptr.bindMemory(to:
HeapObject.
self, capacity:
1)
-
let metaPtr = headObject.pointee.kind.bindMemory(to: hs_swift_class.
self, capacity:
1)
- 使用assumingMemoryBound 案例1: 元组指针类型转换
- assumingMemoryBound:假定内存绑定、告诉编译器当前绑定的类型、不需要进行编译检查
-
var tul = (
10,
20)
-
withUnsafePointer(to: &tul) { (tulPtr:
UnsafePointer<(
Int,
Int)>)
in
-
assuminMemoryBound 假定内存绑定、不需要进行编译检查
-
testPointer(
UnsafeRawPointer(tulPtr).assumingMemoryBound(to:
Int.
self))
-
}
-
func testPointer(_ p : UnsafePointer<Int>){
-
print(p)
-
print(p.pointee)
//输出首地址值:10
-
print((p[
0],p[
1]))
//(10,20)
-
/*
-
x/8g 0x000000010000c4b0
-
0x10000c4b0: 0x000000000000000a 0x0000000000000014
-
*/
-
}
案例2: 使用assumingMemoryBound 获取结构体的属性的指针
-
struct HeapObject {
-
var strongref =
10
-
var unownedRef =
20
-
}
-
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))
-
}
- withMemoryRebound:临时更改内存绑定类型、出了作用域将还原为原有类型。
- 案例使用:
-
struct HeapObjecter{
-
var strongref =
15
-
var unownedRef =
25
-
}
-
var tt =
HeapObjecter()
-
withUnsafePointer(to: &tt) { (ptr:
UnsafePointer<
HeapObjecter>)
in
-
ptr.withMemoryRebound(to:
Int.
self, capacity:
1) { (temp)
in
-
testPointer(temp)
-
}
-
}
-
func testPointer(_ p:UnsafePointer<Int>) {
-
print(p)
-
print(p.pointee)
-
print((p[
0],p[
1]))
-
}
转载:https://blog.csdn.net/SharkToping/article/details/117253587
查看评论