Swift基础语法(十七)Swift的指针实现

Swift基础语法文章汇总

本文主要介绍Swift的指针类型,本质也是地址,但是Swift提供专门的指针类型存储地址。

主要内容:

  1. 指针类型的认识
  2. 指针类型的使用
  3. 类型转换

1、指针认识

Swift中也有专门的指针类型,这些都被定性为“Unsafe”(不安全的),Swift中并不会简单的认为地址就是一个指针,而是有专门的类型进行包装。只要获取到地址就可以对数据进行无访问限制的操作,因此是不安全的。

指针类型:

指针类型 认识
UnsafePointer< Pointee > 类似于 const Pointee *
UnsafeMutablePointer< Pointee > 类似于 Pointee *
UnsafeRawPointer 类似于 const void *
UnsafeMutableRawPointer 类似于 void *

说明:
1、指针都是不安全的,因此都是Unsafe
2、没有Mutalbe的表示仅可读指针指向的内存,带有Mutable表示可读可写
3、< Pointee >是泛型,表示指针的类型
4、带Raw的都是不支持泛型的,所以都是void类型,类型不定

2、指针的使用

2.1 带泛型

代码:

带泛型指针.png

说明:
1、通过指针的pointee来拿到内存数据
2、依然是取地址符拿到指针,只不过需要存储到Swift提供的指针类型中
3、注意Mutable的可以进行修改

2.2 无泛型

代码:

无泛型指针.png

说明:
1、没有设置类型,需要自己设置一下类型
2、注意赋值为load和取值为storeBytes即可

2.3 通过指针遍历数组

代码:

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. 这种遍历方式中stop参数其实就是一个指针类型()
  2. 指针拿到自己的pointee就可以进行修改了。

3、获取指针变量

3.1 获取变量的指针

3.1.1 拿到带泛型的指针

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

说明:

  • with开头的可以获取,最后一个参数是闭包表达式

withUnsafeMutablePointer方法认识:

@inlinable public func withUnsafeMutablePointer<T, Result>(to value: inout T, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result

说明:
1、第一个参数传的就是指针
2、第二个参数是一个闭包表达式,获取最终的Result
3、闭包表达式的参数其实就是传入的指针
4、并且可以看到闭包表达式返回的东西就是这个withUnsafePointer返回的东西

3.1.2 拿到无泛型的指针

//无泛型指针
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) // 33

说明:

  • 这里是通过无泛型指针的初始化器来设置的,传入的就是带泛型的指针,所以可以直接传入$0

3.1.3 拿到变量的指针

代码:

变量指针.png

说明:

  • 这里很明显ptr拿到的是person变量的地址值。指针的本意嘛,不用多言。

3.1.4 拿到对象的指针

方式一:直接获取对象地址作为指针

class Person {
    var age: Int
    init (age: Int) {
        self.age = age
    }
}
var person = Person(age: 18)
var ptr = withUnsafePointer(to: &person) { $0 }
print("变量指针:",ptr)

var personPointer = UnsafeMutableRawPointer?(bitPattern: ptr)
print("对象指针:",personPointer)

说明:
1、调用bitPattern初始化器,里面传入的是对象的地址,此时就可以将该地址包装成指针,也就是放到一个全局区/栈
2、因为传入的参数不一定是正确的,所以是可失败的初始化器

方式二:通过变量获取变量内容作为指针

对象指针.png

说明:
1、这里传入person变量,unsafeBitCast函数就可以拿到这个变量的内容赋值给ptr
2、并且设置的类型就是UnsafeRawPointer。
3、通过这种方式就可以很方便的得到对象的堆空间地址

3.2 创建一个无指向的指针

方式一:

//方式一:
var ptr = malloc(16)
ptr?.storeBytes(of: 10, as: Int.self)
ptr?.storeBytes(of: 20, toByteOffset: 8, as: Int.self)
free(ptr)//释放内存

说明:
1、malloc创建一个空间,此时拿到的ptr的类型为:(注意肯定为可选项)
2、按照正常的添加流程进行添加。注意总共16个字节,一次性赋值只赋给了前8个字节。所以还需要再赋后8个字节,toByteOffset是偏移量

方式二:

//方式二:
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)
print(ptr.load(as: Int.self)) // 11
print(ptr.advanced(by: 8).load(as: Int.self)) // 22
ptr.deallocate()

说明:
1、通过allocate进行创建,填入字节数和对齐数
2、advanced(by: 8)是将ptr指针偏移8个字节,并且返回一个指针。所以它得到的就是后8个字节的指针
3、最后需要通过deallcate销毁

方式三:

//方式三:
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)
ptr.initialize(to: 11)
ptr.successor().initialize(to: 22)
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、在设置值时,可以直接用initialize(repeating: ,count:)重复设置两个值,每个都是10
3、也可以用initialize()只设置第一个值
4、ptr.successor()的作用就是偏移8个字节拿到其指针
5、(ptr + 1)是指针偏移,直接偏移8个字节
6、这里ptr+1、ptr[1]等价的
7、最后需要销毁内存

注意:无泛型指针会进行字节偏移,而不是指针偏移:如果是泛型指针,因为已经知道占用内存大小了,所以是可以进行指针偏移的,如果是非泛型指针,不能进行指针偏移,因为不知道一次性偏移多少

4、类型转换

第一种:非泛型指针的初始化:

var ptr = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0) }
var ptr2 = withUnsafePointer(to: &age) { UnsafeRawPointer($0) }

说明:
1、泛型指针转非泛型指针可以通过非泛型指针的初始化器来设置

第二种:assumingMemoryBound:

assumingMemoryBound方式转换类型.png

说明:
1、非泛型指针转泛型指针可以通过这个方法来转

第三种:unsafeBitCast:
转换时会忽略数据类型的强制转换,不会因为数据类型的变化而改变原来的内存数据

unsafeBitCast类型转换.png

说明:

  1. 正常的数据类型转换,会改变存储的数据
  2. 通过unsafeBitCast的转换不会改变内存数据
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容