• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >swift > Swift中的指针操作详解

Swift中的指针操作详解

作者:Swiftyper 字体:[增加 减小] 来源:互联网 时间:2017-05-28

Swiftyper 通过本文主要向大家介绍了taylor swift,swift,swift code是什么意思,swift bic,taylor swift好听的歌等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

前言

Objective-C和C语言经常需要使用到指针。Swift中的数据类型由于良好的设计,使其可以和基于指针的C语言API无缝混用。但是语法上有很大的差别。

默认情况下,Swift 是内存安全的,这意味着它禁止我们直接操作内存,并且确保所有的变量在使用前都已经被正确地初始化了。但是,Swift 也提供了我们使用指针直接操作内存的方法,直接操作内存是很危险的行为,很容易就出现错误,因此官方将直接操作内存称为 “unsafe 特性”。

一旦我们开始直接操作内存,一切就得靠我们自己了,因为在这种情况下编译能给我们提供的帮助实在不多。正常情况下,我们在与 C 进行交互,或者我们需要挖掘 Swift 内部实现原理的时候会需要使用到这个特性。

Memory Layout

Swift 提供了 MemoryLayout 来检测特定类型的大小以及内存对齐大小:

MemoryLayout<Int>.size // return 8 (on 64-bit)
MemoryLayout<Int>.alignment // return 8 (on 64-bit)
MemoryLayout<Int>.stride // return 8 (on 64-bit)
MemoryLayout<Int16>.size // return 2
MemoryLayout<Int16>.alignment // return 2
MemoryLayout<Int16>.stride // return 2
MemoryLayout<Bool>.size // return 2
MemoryLayout<Bool>.alignment // return 2
MemoryLayout<Bool>.stride // return 2
MemoryLayout<Float>.size // return 4
MemoryLayout<Float>.size // return 4
MemoryLayout<Float>.alignment // return 4
MemoryLayout<Double>.stride // return 8
MemoryLayout<Double>.alignment // return 8
MemoryLayout<Double>.stride // return 8
</div>

MemoryLayout<Type> 是一个用于在编译时计算出特定类型(Type)的 size, alignment 以及 stride 的泛型类型。返回的数值以字节为单位。例如 Int16 类型的大小为 2 个字节,内存对齐为 2 个字节以及当我们需要连续排列多个 Int16 类型时,每一个 Int16 所需要占用的大小(stride)为 2 个字节。所有基本类型的 stride 都与 size 是一致的。

接下来,看看结构体类型的 MemoryLayout:

struct EmptyStruct {}
MemoryLayout<EmptyStruct>.size // returns 0
MemoryLayout<EmptyStruct>.alignment // returns 1
MemoryLayout<EmptyStruct>.stride // returns 1
struct SampleStruct {
 let number: UInt32
 let flag: Bool
}
MemoryLayout<SampleStruct>.size // returns 5
MemoryLayout<SampleStruct>.alignment // returns 4
MemoryLayout<SampleStruct>.stride // returns 8
</div>

空结构体的大小为 0,内存对齐为 1, 表明它可以存在于任何一个内存地址上。有趣的是 stride 为 1,这是因为尽管结构为空,但是当我们使用它创建一个实例的时候,它也必须要有一个唯一的地址。

对于 SampleStruct,它所占的大小为 5,但是 stride 为 8。这是因为编译需要为其填充空白的边界,使其符合它的 4 字节内存边界对齐。

再来看看类:

class EmptyClass {}
MemoryLayout<EmptyClass>.size // returns 8 (on 64-bit)
MemoryLayout<EmptyClass>.alignment // returns 8 (on 64-bit)
MemoryLayout<EmptyClass>.stride // returns 8 (on 64-bit)
class SampleClass {
 let number: Int64 = 0
 let flag: Bool = false
}
MemoryLayout<SampleClass>.size // returns 8 (on 64-bit)
MemoryLayout<SampleClass>.aligment // returns 8 (on 64-bit)
MemoryLayout<SampleClass>.stride // returns 8 (on 64-bit)
</div>

由于类都是引用类型,所以它所有的大小都是 8 字节。

关于 MemoryLayout 的更多详细信息可以参考 Mike Ash 的演讲。

指针

一个指针就是对一个内存地址的封装。在 Swift 当中直接操作指针的类型都有一个 “unsafe” 前缀,所以它的指针类型称为 UnsafePointer。这个前缀似乎看起来很令人恼火,不过这是 Swift 在提醒你,你现在正在跨越雷池,编译器不会对这种操作进行检查,你需要对自己的代码承担全部的责任。

Swift 中包含了一打类型的指针类型,每个类型都有它们的作用和目的,使用适当的指针类型可以防止错误的发生并且更清晰地表达开发者的意图,防止未定义行为的产生。

Swift 的指针类型使用了很清晰的命名,我们可以通过名字知道这是一个什么类型的指针。可变或者不可变,原生(raw)或者有类型的,是否是缓冲(buffer)类型,这三种特性总共组合出了 8 种指针类型。

接下来的几个小节会详细介绍这几种指针类型。

使用原生(Raw)指针

在 Playground 中添加如下代码:

// 1
let count = 2
let stride = MemoryLayout<Int>.stride
let alignment = MemoryLayout<Int>.alignment
let byteCount = stride * count
 
// 2
do {
 print("Raw pointers")
 
 // 3
 let pointer = UnsafeMutableRawPointer.allocate(bytes: byteCount, alignedTo: alignment)
 // 4
 defer {
 pointer.deallocate(bytes: byteCount, alignedTo: alignment)
 }
 
 // 5
 pointer.storeBytes(of: 42, as: Int.self)
 pointer.advanced(by: stride).storeBytes(of: 6, as: Int.self)
 pointer.load(as: Int.self)
 pointer.advanced(by: stride).load(as: Int.self)
 
 // 6
 let bufferPointer = UnsafeRawBufferPointer(start: pointer, count: byteCount)
 for (index, byte) in bufferPointer.enumerated() {
 print("byte \(index): \(byte)")
 }
}
</div>

在这个代码段中,我们使用了 Unsafe Swift 指针去存储和读取两个整型数值。

接下来是对这段代码的解释:

1、声明了接下来都会用到的几个常量:

  • count 表示了我们要存储的整数的个数
  • stride 表示了 Int 类型的 stride
  • alignment 表示了 Int 类型的内存对齐
  • byteCount 表示占用的全部字节数

2、使用 do 来增加一个作用域,让我们可以在接下的示例中复用作用域中的变量名

3、使用 UnsafeMutableRawPointer.allocate 方法来分配所需的字节数。我们使用了 UnsafeMutableRawPointer,它的名字表明这个指针可以用来读取和存储(改变)原生的字节。

4、使用 defer 来保证内存得到正确地释放。操作指针的时候,所有内存都需要我们手动进行管理。

5、storeBytes 和 load 方法用于存储和读取字节。第二个整型数值的地址通过对 pointer 的地址前进 stride 来得到。因为指针类型是 Strideable 的,我们也可以直接使用指针算术运算 (pointer+stride).storeBytes(of: 6, as: Int.self)。

6、UnsafeRawBufferPointer 类型以一系列字节的形式来读取内存。这意味着我们可以这些字节进行迭代,对其使用下标,或者使用 filter,map 以及 reduce 这些很酷的方法。缓冲类型指针使用了原生指针进行初始化。

使用类型指针

我们可以使用类型指针实现跟上面代码一样的功能,并且更简单:

do {
 print("Typed pointers")
 
 let pointer = UnsafeMutablePointer<Int>.allocate(capacity: count)
 pointer.initialize(to: 0, count: count)
 defer {
 pointer.deinitialize(count: count)
 pointer.deallocate(capacity: count)
 }
 
 pointer.pointee = 42
 pointer.advanced(by: 1).pointee = 6
 pointer.pointee
 pointer.advanced(by: 1).pointee
 
 let bufferPointer = UnsafeBufferPointer(start: pointer, count: count)
 for (index, value) in bufferPointer.enumerated() {
 print("value \(index): \(value)")
 }
}
</div>

注意到以下几点不同:

  • 我们使用了 UnsafeMutablePointer.allocate 进行内存的分配。指定的泛型参数让 Swif
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Swift 环境搭建
  • Swift 基本语法
  • Swift 数据类型
  • Swift 变量
  • Swift 常量
  • Swift 运算符
  • Swift 条件语句
  • Swift 循环
  • Swift 字符串
  • Swift 字符(Character)

相关文章

  • 2017-05-22Swift 属性
  • 2017-05-28在Mac OS的终端中运行Swift应用的方法
  • 2017-05-28微信小程序 navigator 跳转url传递参数
  • 2017-05-28使用Post方法模拟登陆爬取网页的实现方法
  • 2017-05-28深入解析Swift编程中的构造方法
  • 2017-05-28Mybatis传list参数调用oracle存储过程的解决方法
  • 2017-05-28Swift教程之方法详解
  • 2017-05-28IOS 实现简单的弹幕功能
  • 2017-05-28Swift编程中数组的使用方法指南
  • 2017-05-28Swift中的指针操作详解

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • mybatis基本实例详解
    • 详解Swift中的函数及函数闭包使用
    • Objective-c代码如何移植为Swift代码 Objective-c代码转移到Swift过程介绍
    • Swift操作Quartz 2D进行简单的绘图与坐标变换的教程
    • Servlet3.0实现文件上传的方法
    • 用Swift编写自动录音器
    • Swift算法实现逐字翻转字符串的方法示例
    • 详解Swift编程中下标的用法
    • Swift代码实现冒泡排序算法的简单实例
    • 解析Swift中的泛型支持与使用

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有