关于Swift中的指针的那些事
前言
在Objective-c的世界中,一切对象都是指针。它是一种运行时语言,具体指针的对象类型将会在运行时,由系统分配。这样虽然自由,但是却并不安全。
Swift世界就不一样了,Swift的世界很安全(至少大部分时候情况如此)。我们不必为对象运行时的类型担忧,这是Swift为我们构筑的一层堡垒。但是在一些时候,这层堡垒也成为束缚我们行为的操作。
正文
Swift也为操作指针这种不安全行为提供了支持。
MemoryLayout
MemoryLayout是Swift 为结构体struct等一些需要获取具体内存空间大小定义的枚举。
它包含一系列方法,可以使我们更方便的使用。
主要属性就是三个:
/// 对应类型的实例在内存占用的真实字节大小
public static var size: Int { get }
/// 对应类型的实例在内存经过对齐后占用的字节大小 (内存对齐请参照百度百科,链接将会在下文给出)
public static var stride: Int { get }
/// 默认内存对齐单位
public static var alignment: Int { get }
复制代码
内存对齐百度百科: baike.baidu.com/item/内存对齐/9…
这三个属性也是我们经常使用的,对应还有三个从实例对象中获取的方法
playgroud 介绍代码
struct Test {
let res1: Bool = false
let res2: Int = 0
let res3: Bool = false
}
print("\(MemoryLayout<Test>.stride)") // 24
复制代码
因为这个类不是我们首要要介绍的,所以就只是大概介绍
内存指针
指针定义:
在计算机科学中,**指针(Pointer)**是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
节选自百度百科: baike.baidu.com/item/指针/287…
Swift中认为所有的指针相关操作都是不安全的,所以所有指针相关的结构体都会包含有前缀Unsafe
Swift中一共有8个结构体
| Swift | Objective-c | 描述 |
|---|---|---|
UnsafePointer<T> |
const T * |
指针及其所指向的内存内容均不可变 |
UnsafeMutablePointer<T> |
T * |
指针及其所指向的内存内容均可变 |
UnsafeBufferPointer<T> |
const T * [] |
是一个指针数组内容均不可变 |
UnsafeMutableBufferPointer<T> |
T * [] |
|
UnsafeRawPointer |
const void * |
|
UnsafeMutableRawPointer |
void * |
|
UnsafeBufferRawPointer |
void * [] |
首先要说一个实例类对象如何转化为指针
UnsafePointer代码展示:
struct Obj {
var name: Int = 5
}
var obj = Obj()
let pointer = withUnsafePointer(to: &obj, {$0})
print("\(pointer.pointee)")
复制代码
这里注意了,UnsafePointer.pointee只有get方法,也就是相当于我们获取了一个let的对象,遵从于let的相关要求。
注:这里多介绍一下let和var的区别
let和var都是swift声明变量时候的前缀。在程序中,当我们声明变量的时候,在真实运行时候的环境里,程序便会为我们声明的变量初始化对应的内存。
let声明的变量的内存内容,在声明初始化过后便不再可变
var声明的变量的内存内容,在随后可以随时被修改。这里我们使用的是内存内容,也就是抽象的内存地址里的那些0、1的值。
对于
class,let和var的区别是这个变量能不能再被赋值一个新的类对象,而对原有对象的相关存储属性的修改,并不受影响。这是因为class的对象在声明时候的堆栈内存内容,只有8个字节(我们可以使用MemoryLayout获取),真实对象的存储在其他位置。所以我们能修改let指向的值对于
struct,let和var的区别就是let创建的对象,不论属性是用let还是var,我们都无法直接修改值。只能修改var修饰的。这个是因为struct对象是直接存储在声明时候的内存内容里。
对于UnsafeMutablePointer来说,pointee便是set和get方法了,也就是说,我们可以直接修改对应内存地址的值了。
这里展示下如何获取UnsafeMutablePointer与修改相关值
struct Obj {
var name: Int = 5
init(name: Int = 5) {
self.name = name
}
}
var obj = Obj()
let pointer = withUnsafeMutablePointer(to: &obj, {$0})
print("Obj: \(obj)")
pointer.pointee = Obj(name: 10)
print("\(pointer.pointee)")
print("Obj: \(obj)")
复制代码
当运行这段代码的时候,我们可以看到,obj的内容也随着指针变化了。
注:obj只能使用var声明,因为Unsafe类的调用需要使用&,同时有可能产生内存内容的变化,因此let定义下不符合相关要求。
接下来是我要讲的就是Swift中等同于C语言中void *的指针UnsafeRawPointer
有可能到这里就会有疑问了,我们已经有了UnsafePointer了,这个UnsafeRawPointer究竟有什么用呢?
在苹果的官方文档中,关于UnsafeRawPointer的定义为
A raw pointer for accessing untyped data.
一个用来访问未定义类型的指针
Overview
The UnsafeRawPointer type provides no automated memory management, no type safety, and no alignment guarantees. You are responsible for handling the life cycle of any memory you work with through unsafe pointers, to avoid leaks or undefined behavior.
UnsafeRawPointer 提供了没有自动内存管理,没有类型安全,与内存对齐控制保证。你有义务去自己管理你通过指针引用的任何内存的声明周期,以避免内存泄漏或者其余未定义(不安全)的行为
Memory that you manually manage can be either untyped or bound to a specific type. You use the UnsafeRawPointer type to access and manage raw bytes in memory, whether or not that memory has been bound to a specific type.
你手动管理的内存可以是未定义内存的,或者是被定义到一个指定的类型的。你可以使用UnsafeRawPointer去访问和管理未被定义的内存字节,而无需在意这段内存是否已经被绑定到一个指定的类型。
官方定义是这样的,大致思路就是,如果你有需求需要自己管理内存的时候,使用这个类。一般就是我们操作底层的一些代码,这个会需要被当成参数传入。
代码示例:
var i = 2
let pointerRaw = withUnsafeBytes(of: &i, {$0})
guard let pointer = pointerRaw.bindMemory(to: Int.self).baseAddress else { fatalError("这段代码理论上不能执行到这") }
let j = pointer.pointee
print("j:\(j)")
复制代码
以上代码就是转换rawPointer和pointer的例子了。剩下的是bufferPointer,因为使用的地方较少了,故此不深入介绍了。
总结
指针相关中最重要的几个操作就是指针的生成,与将指针转化成实例对象。其中重要的就是pointee和几个withUnsafeXX的全局函数。
在swift中,指针的世界并不复杂,所有指针的操作都能转化为8个UnsafeXX类。我们的使用也是基于此的,我们如果使用某些底层方法需要指针,这个时候只需要将相应的指针对象生成即可传入。
作者:chouheiwa
链接:https://juejin.im/post/5c2cc325518825480635dd39
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关于Swift中的指针的那些事的更多相关文章
- Swift中的指针类型
Swift编程语言为了能与Objective-C与C语言兼容,而引入了指针类型.尽管官方不建议频繁使用指针类型,但很多时候,使用指针能完成更多.更灵活的任务.比如,我们要实现一个交换两个整数值的函数的 ...
- Swift 中的指针使用
SWIFT 中 指针被映射为泛型 UnsafePointer<T> UnsafeMutablePointer<T> 表示一组连续数据指针的 UnsafeBufferPoint ...
- 一图总结C++中关于指针的那些事
指向对象的指针.指向数据成员的指针,指向成员函数的指针: 数组即指针,数组的指针,指针数组: 指向函数的指针,指向类的成员函数的指针,指针作为函数參数,指针函数: 指针的指针,指向数组的指针:常指针. ...
- Swift 中 String 与 CChar 数组的转换
在现阶段Swift的编码中,我们还是有很多场景需要调用一些C函数.在Swift与C的混编中,经常遇到的一个问题就是需要在两者中互相转换字符串.在C语言中,字符串通常是用一个char数组来表示,在Swi ...
- Swift——(六)Swift中的值类型
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/twlkyao/article/details/34855597 在Swift中,结构体和枚举 ...
- Swift中如何转换不同类型的Mutable指针
在Swift中我们拥有强大高级逻辑抽象能力的同时,低级底层操作被刻意的限制了.但是有些情况下我们仍然想做一些在C语言中的hack工作,下面本猫就带大家看一看如何做这样的事. hacking is ha ...
- swift 中指针的使用UnsafeMutablePointer
在swift中已经弱化了指针的使用,可以这么使用 let s: NSRange = NSMakeRange(, ) let at = UnsafeMutablePointer<NSRange&g ...
- Swift中对C语言接口缓存的使用以及数组、字符串转为指针类型的方法
由于Swift编程语言属于上层编程语言,而Swift中由于为了低层的高性能计算接口,所以往往需要C语言中的指针类型,由此,在Swift编程语言刚诞生的时候就有了UnsafePointer与Unsafe ...
- 寒哥带你深入了解下Swift中的Value Type
http://www.cocoachina.com/swift/20150923/13539.html 关于开发到底使用ValueType 值类型还是Reference Type 引用类型,关于这个, ...
随机推荐
- [PHP] 算法-将一个字符串转换成一个整数的PHP实现
题目描述 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一 ...
- 深入理解JAVA中的NIO
前言: 传统的 IO 流还是有很多缺陷的,尤其它的阻塞性加上磁盘读写本来就慢,会导致 CPU 使用效率大大降低. 所以,jdk 1.4 发布了 NIO 包,NIO 的文件读写设计颠覆了传统 IO 的设 ...
- eclipse下svn的使用
描述:本篇用解决下面的案例中的问题来描述eclipse svn插件的使用. a.案例 某研发团队开发了一款名为App,目前已发布v1.0版本.此项目初期已有部分基础代码, 研发团队再此基础代码上经过3 ...
- JavaScript Array常用属性和方法
Array的length属性可以通过赋值改变,但这样会导致Array原有的大小发生改变. var a = ["I", "Love", "You&quo ...
- Java多线程面试题整理
部分一:多线程部分: 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. ...
- Android 9.0新特性
1.全面屏支持,Android P加入了对刘海屏的支持,谷歌称之为凹口屏幕(display with a cutout).借助最新的提供的DisplayCutout类,开发者可以找到非功能区域的位置和 ...
- C程序
/* 不适用C库函数,只是用 C 语言实现函数 void* memcpy( void *dst, const void *src, size_t len ) memmove 函数的功能是拷贝 src ...
- 章节五、2-Package包和权限修饰符
一.Package包 为了更好的组织类,java提供了包机制,用于区别类名的命名空间. 包的作用: 1.把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2.如同文件夹一样,包也采用了 ...
- android adb 流程原理代码分析(一)
由于要用到adb的知识,但是对adb啥也不了解,看了下android的代码,adb的源码在system/core/adb下面,然后网上搜下了资料,发现很多大神的源码分析,瞬间信心爆棚,把大神写的博客都 ...
- spring-AOP(面向切面编程)-xml方式配置
AOP是针对面向对象编程的一种补充,有时使用面向对象不能很好完成一些额外的功能业务时,可以采用AOP来进行补充. AOP术语: 切面(Aspect) 切面是用于编写切面逻辑的一个类,这个类很类似于JD ...