指针
Swift中也有专门的指针类型,可以直接访问内存,这些都被定性为“Unsafe”(不安全的),常见的有以下4种类型
markdown
* `UnsafePointer<Pointee>` 类似于 `const Pointee *`, 不可以修改内存,Pointee是泛型,传入什么类型就是什么类型
* `UnsafeMutablePointer<Pointee>` 类似于 `Pointee *`,可以修改内存
* `UnsafeRawPointer` 类似于 `const void *`,不带泛型,根据设置的类型获取固定的字节
* `UnsafeMutableRawPointer` 类似于 `void *`,不带泛型,根据设置的类型修改固定的字节1
2
3
4
2
3
4
示例
UnsafePointer 和 UnsafeMutablePointer 的用法,获取到变量的地址,进行打印或修改
swift
var age = 10
func test1(_ ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 10
}
func test2(_ ptr: UnsafePointer<Int>) {
print(ptr.pointee)
}
test1(&age)
test2(&age) // 20
print(age) // 201
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
UnsafeMutableRawPointer 和 UnsafeRawPointer 不带泛型,根据设置的类型修改固定的字节
swift
var age = 10
func test3(_ ptr: UnsafeMutableRawPointer) {
ptr.storeBytes(of: 20, as: Int.self)
}
// 不知道是什么类型的数据,需要取多少个字节,传对应的类型
func test4(_ ptr: UnsafeRawPointer) {
print(ptr.load(as: Int.self))
}
test3(&age)
test4(&age) // 20
print(age) // 201
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
在数组遍历时常用的方法
swift
var arr = NSArray(objects: 11, 22, 33, 44)
arr.enumerateObjects { (obj, idx, stop) in
print(idx, obj)
if idx == 2 { // 下标为2就停止遍历
stop.pointee = true
}
}1
2
3
4
5
6
7
2
3
4
5
6
7
获得指向某个变量的指针
withUnsafeMutablePointerwithUnsafePointer
swift
var age = 11
var ptr1 = withUnsafeMutablePointer(to: &age) { $0 }
var ptr2 = withUnsafePointer(to: &age) { $0 }
ptr1.pointee = 22
print(ptr2.pointee) // 22
print(age) // 22
var ptr3 = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0) }
var ptr4 = withUnsafePointer(to: &age) { UnsafeRawPointer($0) }
ptr3.storeBytes(of: 33, as: Int.self)
print(ptr4.load(as: Int.self)) // 33
print(age) // 331
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
withUnsafePointer函数的实现可以看做下面这种写法,函数的返回值其实就是闭包的返回值,只是写的很绕:
swift
func withUnsafePointer<Result,T>(to: UnsafePointer<T>,body:(UnsafePointer<T>) -> Result) -> Result{
return body(to)
}1
2
3
2
3
获得指向堆空间实例的指针
swift
class Person {}
var person = Person()
var ptr = withUnsafePointer(to: &person) { UnsafeRawPointer($0) }
var heapPtr = UnsafeRawPointer(bitPattern: ptr.load(as: UInt.self))
print(heapPtr!)1
2
3
4
5
2
3
4
5
创建指针
UnsafeRawPointer创建指针
swift
var ptr = UnsafeRawPointer(bitPattern: 0x100001234)1
malloc创建指针
swift
// 创建 16个字节
var ptr = malloc(16)
// 存
ptr?.storeBytes(of: 11, as: Int.self)
ptr?.storeBytes(of: 22, toByteOffset: 8, as: Int.self) //偏移8个字节
// 取
print((ptr?.load(as: Int.self))!) // 11
print((ptr?.load(fromByteOffset: 8, as: Int.self))!) //取后8个字节 22
// 销毁
free(ptr)1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
UnsafeMutableRawPointer创建指针
swift
// 创建指针
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
// 存
ptr.storeBytes(of: 11, as: Int.self)
ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self) //偏移8个字节 进行赋值
// 取
print(ptr.load(as: Int.self)) // 11
print(ptr.advanced(by: 8).load(as: Int.self)) // 22
// 释放
ptr.deallocate()1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
UnsafeMutablePointer创建指针
swift
// 创建指针, 3表示容量 24个字节 3 * 8
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)
// 初始化前8个字节
ptr.initialize(to: 11)
// 初始化中间8个字节
ptr.successor().initialize(to: 22)
// 初始化后8个字节
ptr.successor().successor().initialize(to: 33)
print(ptr.pointee) // 11
print((ptr + 1).pointee) // 22
print((ptr + 2).pointee) // 33
print(ptr[0]) // 11
print(ptr[1]) // 22
print(ptr[2]) // 33
// 释放
ptr.deinitialize(count: 3)
ptr.deallocate()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UnsafeMutablePointer示例演示
swift
class Person {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
deinit { print(name, "deinit") }
}
var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "Jack"))
(ptr + 1).initialize(to: Person(age: 11, name: "Rose"))
(ptr + 2).initialize(to: Person(age: 12, name: "Kate"))
// Jack deinit
// Rose deinit
// Kate deinit
ptr.deinitialize(count: 3) // 注意初始化几个就要销毁几个,不然容易内存泄漏
ptr.deallocate()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
指针之间的转换
- 非泛型指针 转换成 泛型指针
swift
// 初始化16个字节
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
// assumingMemoryBound 转换 泛型指针
ptr.assumingMemoryBound(to: Int.self).pointee = 11
// 后8个字节指向Double类型
(ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22.0
// unsafeBitCast 转换 泛型指针
print(unsafeBitCast(ptr, to: UnsafePointer<Int>.self).pointee) // 11
print(unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self).pointee) // 22.0
// 销毁
ptr.deallocate()1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
unsafeBitCast是忽略数据类型的强制转换,不会因为数据类型的变化而改变原来的内存数据,类似于C++中的reinterpret_cast。
swift
class Person {}
var person = Person()
// ptr 指向 person 对象
var ptr = unsafeBitCast(person, to: UnsafeRawPointer.self)
print(ptr)1
2
3
4
5
2
3
4
5
unsafeBitCast是对内存的强制转换,比如Int类型的10二进制是0xa,通过unsafeBitCast转换成Double类型后在内存中还是0xa