天天看点

iOS开发-Swift进阶之指针!

本文主要介绍swift中的指针

iOS开发-Swift进阶之指针!

swift中的指针分为两类

<code>typed pointer</code> <code>指定数据类型</code>指针,即 <code>unsafepointer&amp;lt;t&amp;gt;</code>,其中t表示泛型

<code>raw pointer</code> <code>未指定数据类型</code>的指针(原生指针) ,即<code>unsaferawpointer</code>

swift与oc指针对比如下:

swift

oc

说明

unsafepointer&lt;t&gt;

const t *

指针及所指向的内容都不可变

unsafemutablepointer

t *

指针及其所指向的内存内容均可变

unsaferawpointer

const void *

指针指向未知类型

unsafemutablerawpointer

void *

原生指针:是指未指定数据类型的指针,有以下说明

对于<code>指针</code>的<code>内存管理</code>是需要<code>手动</code>管理的

指针在使用完需要<code>手动释放</code>

有以下一段原生指针的使用代码,请问运行时会发生什么?

通过运行发现,在读取数据时有问题,原因是因为读取时指定了每次读取的大小,但是存储是直接在8字节的<code>p</code>中存储了<code>i+1</code>,即可以理解为并没有指定存储时的内存大小

iOS开发-Swift进阶之指针!

修改:通过<code>advanced(by:)</code>指定存储时的步长

修改后的运行结果如下

iOS开发-Swift进阶之指针!
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的ios开发交流群:130 595 548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)

在前几篇文章中,我们获取基本数据类型的地址是通过<code>withunsafepointer(to:)</code>方法获取的

查看<code>withunsafepointer(to:</code>的定义中,第二个参数传入的是闭包表达式,然后通过<code>rethrows</code>重新抛出<code>result</code>(即闭包表达式产生的结果)了,所以可以将闭包表达式进行简写(简写参数、返回值),其中<code>$0</code>表示第一个参数,<code>$1</code>表示第二个参数,以此类推

iOS开发-Swift进阶之指针!

由于<code>withunsafepointer</code>方法中的闭包属于<code>单一表达式</code>,因此可以省略参数、返回值,直接使用<code>$0</code>,$0等价于ptr

访问属性

可以通过指针的<code>pointee</code>属性访问<code>变量值</code>,如下所示

如何改变age变量值?

改变变量值的方式有两种,一种是<code>间接修改</code>,一种是<code>直接修改</code>

<code>间接修改</code>:需要在闭包中直接通过<code>ptr.pointee</code>修改并返回。类似于<code>char *p = “cjl” 中的 *p,因为访问cjl通过 *p</code>

<code>直接修改-方式1</code>:也可以通过<code>withunsafemutablepointer</code>方法,即<code>创建方式一</code>

直接修改方式2:通过<code>allocate</code>创建<code>unsafemutablepointer</code>,需要注意的是

<code>initialize</code> 与 <code>deinitialize</code>是成对的

<code>deinitialize</code>中的count与申请时的capacity需要一致

需要<code>deallocate</code>

定义一个结构体

使用<code>unsafemutablepointer</code>创建指针,并通过指针访问cjlteacher实例对象,有以下三种方式:

方式一:下标访问

方式二:内存平移

方式三:successor

需要注意的是,第二个空间的初始化不能通过<code>advanced(by: memorylayout&amp;lt;cjlteacher&amp;gt;.stride)</code>去访问,否则取出结果是有问题

iOS开发-Swift进阶之指针!

可以通过<code>ptr + 1</code>或者<code>successor()</code> 或者<code>advanced(by: 1)</code>

对比

这里p使用<code>advanced(by: i * 8)</code>,是因为此时并不知道 p 的具体类型,必须指定每次移动的步长

这里的<code>ptr</code>如果使用<code>advanced(by: memorylayout&amp;lt;cjlteacher&amp;gt;.stride)</code>即16*16字节大小,此时获取的结果是有问题的,由于这里知道具体的类型,所以只需要标识<code>指针前进 几步</code>即可,即<code>advanced(by: 1)</code>

定义如下代码

demo1:类的实例对象如何绑定到 结构体内存中?

1、获取实例变量的内存地址

2、绑定到结构体内存,返回值是<code>unsafemutablepointer&amp;lt;t&amp;gt;</code>

3、访问成员变量 <code>pointee.kind</code>

其运行结果如下,有点类似于cf与oc交互的时的所有权的转换

iOS开发-Swift进阶之指针!

create\copy 需要使用retain

不需要获取所有权 使用unretain

将kind的类型改成<code>unsaferawpointer</code>,kind的输出就是地址了

iOS开发-Swift进阶之指针!

demo2:绑定到类结构

将<code>swift</code>中的类结构定义成一个结构体

将t改成绑定到<code>cjl_swift_class</code>

运行结果如下,其本质原因是因为 <code>metaptr</code> 和 <code>cjl_swift_class</code>的类结构是一样的

iOS开发-Swift进阶之指针!

如果将元组传给 函数<code>testpointer</code>,使用方式如下

或者告诉编译器转换成具体的类型

1、定义实例变量

2、获取实例变量的地址,并将strongref的属性值传递给函数

代码如下:

如果方法的类型与传入参数的类型不一致,会报错

iOS开发-Swift进阶之指针!

解决办法:通过<code>withmemoryrebound</code>临时绑定内存类型

指针类型分两种

<code>typed pointer</code> <code>指定数据类型</code>指针,即 <code>unsafepointer&amp;lt;t&amp;gt;</code> + <code>unsafemutablepointer</code>

<code>raw pointer</code> <code>未指定数据类型</code>的指针(原生指针) ,即<code>unsaferawpointer</code> + <code>unsafemutablerawpointer</code>

<code>withmemoryrebound</code>: 临时更改内存绑定类型

<code>bindmemory(to: capacity:)</code>: 更改内存绑定的类型,如果之前没有绑定,那么就是首次绑定,如果绑定过了,会被重新绑定为该类型

<code>assumingmemorybound</code>假定内存绑定,这里就是告诉编译器:我的类型就是这个,你不要检查我了,其实际类型还是原来的类型

继续阅读