指针类型
//基本指针 UnsafePointer<T> const T * UnsafeMutablePointer T * //集合指针 UnsafeBufferPointer const T * //指向一个连续已知类型区域,可以看成一个集合,并支持集合操作 UnsafeMutableBufferPointer T * //指向一个连续已知类型区域,可以看成一个集合,并支持集合操作 //空指针 UnsafeRawPointer const void * UnsafeMutableRawPointer void * UnsafeRawBufferPointer const void * //指向一个连续未知类型区域 UnsafeMutableRawBufferPointer void * //指向一个连续未知类型区域
UnsafePointer 和 UnsafeMutablePointer UnsafePointer只读指针 UnsafeMutablePointer可修改指针
UnsafePointer只读指针 通过UnsafePointer<T>定义一个类型为T的指针,通过pointee成员即可获得T的值。
//UnsafePointer参数只能接收inout修饰的类型,而inout修饰的类型必然是可写的,所以参数只能用var定义 func call(_ p: UnsafePointer<Int>) { print("\(p.pointee)") } var a = 1234 //&a用于传递指针 call(&a) // 打印:1234UnsafeMutablePointer可修改指针 可以通过设置p.pointee 修改指针的值。
func modify(_ p: UnsafeMutablePointer<Int>) { p.pointee = 5678 } var a = 1234 modify(&a) print("\(a)") // 打印:5678UnsafeBufferPointer 集合指针类型 UnsafeBufferPointer指针实现了Collection协议,因此可以直接使用Collection中的各种方法来遍历操作数据,filter,map...等。 Swift的数组提供了函数withUnsafeBufferPointer,通过它我们可以方便的用指针来处理数组。 下面通过withUnsafeBufferPointer获得变量p,p的类型为UnsafeBufferPointer<Int32>,它代表着一整块的连续内存,它是集合类型指针,并且它也支持大部分数组操作。
let a: [Int32] = [1, 2, -1, -2, 5, 6] let p = a.withUnsafeBufferPointer { $0 } print("\(p.count)") // 打印:6 print("\(p[3])") // 打印:-2空指针:UnsafeRawPointer 就像C语言有void*(即空指针)一样,Swift也有自己的空指针,它通过类型UnsafeRawPointer来获得
let rp: UnsafeMutablePointer<CChar> = rRes.value let strLength = rRes.length //将UnsafeMutablePointer<CChar> C语言的char *指针转成 UnsafeMutableRawPointer 的void *任意指针。然后直接取出封装成String字符串 let strRes = String.init(bytesNoCopy: UnsafeMutableRawPointer(mutating: rp), length: Int(strLength), encoding: .utf8, freeWhenDone: false)指针的类型转换
UnsafePointer 基本指针 //将指针的类型转换成一个临时的给定类型,并将指针传递给closure func withMemoryRebound<T, Result>(to: T.Type, capacity: Int, (UnsafePointer<T>) -> Result) -> Result //向下移动一位,并返回一个新的指针 func successor() -> UnsafePointer<Pointee> //向上移动一位,并返回一个新的指针 func predecessor() -> UnsafePointer<Pointee> RawPointer 空指针 //转换给指定类型的指针 func assumingMemoryBound<T>(to: T.Type) -> UnsafeMutablePointer<T> //转换成指定类型的指针,capacity指定了这个指针读取的T数据数量 func bindMemory<T>(to type: T.Type, capacity count: Int) -> UnsafeMutablePointer<T> UnsafeBufferPointer 集合指针 let rpSub:UnsafeMutablePointer<UInt8> = rp.withMemoryRebound(to: UInt8.self, capacity: Int(strLength), { $0 }) let buffer = UnsafeBufferPointer<UInt8>.init(start: rpSub, count: Int(strLength))
指针的操作 指针的辅助函数,通过函数withUnsafePointer,获得指定类型的对应指针
//返回一个T类型指针。将第一个参数T以指针的形式传递给closure func withUnsafePointer<T, Result>(to: T, (UnsafePointer<T>) -> Result) -> Result func withUnsafePointer<T, Result>(to: inout T, (UnsafePointer<T>) -> Result) -> Result func withUnsafeMutablePointer<T, Result>(to: inout T, (UnsafeMutablePointer<T>) -> Result) -> Result func withUnsafePointer<T, Result>(to value: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result定义一个整形a,而p就是指向a的整形指针,它的类型会被自动转换为UnsafePointer<Int>, 第二个参数被简化为了{ $0 },代码块接收一个UnsafePointer<Int>参数,该参数即是a的地址,直接通过$0将它返回,即得到了a的指针,最终它被传给了p。
var a = 1234 let p = withUnsafePointer(to: &a) { $0 } print("\(p.pointee)") // 打印:1234获取指针并进行字节级操作 withUnsafeBytes 如果要对某块内存进行字节级编程。可以通过withUnsafeBytes得到某个类型的数据的字节指针,从而可以对它们进行字节级编程。 因为withUnsafeBytes返回了一个类型UnsafeRawBufferPointer,该类型代表着一个字节级的内存块集合指针,所以以通过下标索引、for循环的方式来处理返回的对象。
var a: UInt32 = 0x12345678 let p = withUnsafeBytes(of: &a) { $0 } var log = "" for item in p { let hex = NSString(format: "%x", item) log += "\(hex)" } print("\(p.count)") // 打印:4 print("\(log)") // 对于小端机器会打印:78563412
通过指针动态创建、销毁内存 使用Swift可以直接操作内存,如可以开辟和管理一块内存,最后释放它,Swift提供了UnsafeMutablePointer的成员函数allocate来处理该工作。
let p = UnsafeMutablePointer<Int32>.allocate(capacity: 1) p.initialize(to: 0) // 初始化 p.pointee = 32 print("\(p.pointee)") // 打印:32 p.deinitialize(count: 1) // 反初始化 p.deallocate()C标准库函数的映射调用 Swift提供了大量的C标准库的桥接方法,我们可以像调用C语言库函数一样它们,如memcpy,strcpy等。
var n = 10086 // malloc let p = malloc(MemoryLayout<Int32>.size)! // memcpy memcpy(p, &n, MemoryLayout<Int32>.size) let p2 = p.assumingMemoryBound(to: Int32.self) print("\(p2.pointee)") // 打印:10086 // strcpy let str = "abc".cString(using: .ascii)! if str.count != MemoryLayout<Int32>.size { return } let pstr = p.assumingMemoryBound(to: CChar.self) strcpy(pstr, str) print("\(String(cString: pstr))") // 打印:abc // strlen print("\(strlen(pstr))") // 打印: 3 // memset memset(p, 0, MemoryLayout<Int32>.size) print("\(p2.pointee)") // 打印:0 // strcat strcat(pstr, "h".cString(using: .ascii)!) strcat(pstr, "i".cString(using: .ascii)!) print("\(String(cString: pstr))") // 打印:hi // strstr let s = strstr(pstr, "i")! print("\(String(cString: s))") // 打印:i // strcmp print("\(strcmp(pstr, "hi".cString(using: .ascii)!))") // 打印:0 // free free(p)
实际使用案例 1.将C函数库返回的char *指针,读取成字符串
let rRes = c_shmread() let rp: UnsafeMutablePointer<CChar> = rRes.value let strLength = rRes.length //1.先将UnsafeMutablePointer<CChar> C语言的char *指针转成 UnsafeMutableRawPointer 的void *任意指针。然后直接取出封装成String字符串 if let strRes = String.init(bytesNoCopy: UnsafeMutableRawPointer(mutating: rp), length: Int(strLength), encoding: .utf8, freeWhenDone: false) { return strRes } else { return "" } //2.使用withMemoryRebound转换指针类型从CChar转成UInt8类型; let rpSub:UnsafeMutablePointer<UInt8> = rp.withMemoryRebound(to: UInt8.self, capacity: Int(strLength), { $0 }) //然后创建集合类型指针UnsafeBufferPointer; let buffer = UnsafeBufferPointer<UInt8>.init(start: rpSub, count: Int(strLength)) buffer.forEach { print($0) } //然后创建Data, 再将data转成String let data = Data(bytes: rpSub, count: Int(strLength)) let str = String(data: data, encoding: String.Encoding.utf8)
参考文章: https://juejin.cn/post/7030789069915291661#heading-6 https://www.jianshu.com/p/a9956ee1ab61 标签:UnsafeMutablePointer,UnsafePointer,类型,let,print,Swift,指针 From: https://www.cnblogs.com/zhou--fei/p/17652559.html