Swift中指针UnsafePointer的常见用法

UnsafePointer,常见,用法,中指针 · 浏览次数 : 34

小编点评

```swift print("\\(p.pointee)") print("\(log)") print("\(p2.pointee)") print("\(String(cString: pstr))") print("\(strlen(pstr))") print("\(strcmp(pstr, "hi".cString(using: .ascii)!))") ``` ``` 3 print("\(p2.pointee)") ``` 这代码展示了如何从 UnsafeMutablePointer<CChar>> 获取 C语言的 char *指针,并从 UnsafeMutableRawPointer 获取 C语言的 char *指针,最后创建 Data, 再将 data 转成 Stringlet。

正文

指针类型
//基本指针
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) // 打印:1234
UnsafeMutablePointer可修改指针
可以通过设置p.pointee 修改指针的值。
func modify(_ p: UnsafeMutablePointer<Int>) {
    p.pointee = 5678
}
var a = 1234
modify(&a)
print("\(a)") // 打印:5678
UnsafeBufferPointer 集合指针类型
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
 
 

与Swift中指针UnsafePointer的常见用法相似的内容:

Swift中指针UnsafePointer的常见用法

指针类型 //基本指针 UnsafePointer const T * UnsafeMutablePointer T * //集合指针 UnsafeBufferPointer const T * //指向一个连续已知类型区域,可以看成一个集合,并支持集合操作 UnsafeMutableBuff

Swift中发布-订阅框架Combine的使用

Combine简介 Combine是一个苹果用来处理事件的新的响应式框架,支持iOS 13及以上版本。 你可以使用Combine去统一和简化在处理类似于target-action,delegate,kvo等事情的代码。 iOS目前已经有第三方的响应式框架了,如:RxSwift、ReactiveCoc

Swift中UITableViewDiffableDataSource的使用

在 iOS 13 中 Apple 为 UITableView 和 UICollectionView 引入了 DiffableDataSource, 让开发者可以更简单高效的实现 UITableView、UICollectionView 的局部数据刷新。 新的刷新的方法为 apply 通过使用 app

Swift中常见的String用法,Array高阶使用,Set集合操作

String字符串常见用法 生成字符串 创建字符串 let greeting = "Hello, world!" let name = String("John") 连接字符串:使用加号(+)或者字符串插值(使用())来将多个字符串连接起来。 var firstName = "John" let l

Swift与OC混编

Swift调OC 在Swift项目中调用OC类中的方法需要有个{targetName}-Bridging-Header.h文件,在这个文件中导入OC要暴露给Swift的类。 {targetName}-Bridging-Header.h文件的创建有2种方式 1.自己手动创建,然后在配置文件的Objec

modulemap的使用方法

modulemap的作用 modulemap 文件是用来解决 C,Object-C,C++ 代码在 Swift 项目中集成的问题的。 在 Swift 项目中,如果需要使用 C,Object-C 或者 C++ 代码,需要将相应的头文件和源文件导入到项目中,并且需要手动管理它们之间的依赖关系。导致项目结

Swift开发基础06-闭包

Swift的闭包(Closures)是一种将功能块和上下文整合并演示在代码中的一种手段。闭包可以捕获并存储其上下文中的变量和常量。与普遍存在于其他语言的匿名函数(如Python的lambda、JavaScript的函数表达式)类似,Swift的闭包提供了强大的功能,并在很多场景中替代了函数。 闭包有

Swift之struct二进制大小分析

随着Swift的日渐成熟和给开发过程带来的便利性及安全性,京喜App中的原生业务模块和基础模块使用Swift开发占比逐渐增高。本次讨论的是struct对比Class的一些优劣势,重点分析对包体积带来的影响及规避措施。

Swift下Data处理全流程:从网络下载,数模转换,本地缓存到页面使用

Swift下将网络返回json数据转换成struct 假如网络请求返回的数据结构是一个深层嵌套的Json 首先要通过key-value取出这个json中的数据源 // 将返回的json字符串转Dictory let json = """ { "name": "jack", "age": 20, "d

Swift函数调用方式浅析

函数的调用机制 函数的调用机制是在函数调用时通过那种路径走到最终调用函数地址的机制。 在编程语言中,函数的调用机制有三种 1.静态调用:编译期就确定了函数内存地址,执行效率最高,还可以使用编译器优化如:inline函数内联提升执行效率。缺点:因为函数调用的内存地址在编译期已经确定,则无法支持继承等动