浅谈 Swift 2 中的 Objective-C 指针
2015-11-04 21:59
429 查看
浅谈 Swift 2 中的 Objective-C 指针
2015-09-07 499文章目录
1. 在 Swift 中读 C 指针
2. 在 Swift 中创建 C 指针
3. 总结
作者:Jameson Quave,原文链接,原文日期:2015/08/23
译者:mmoaay;校对:numbbbbb;定稿:shanks
本文写于 2015 年 8 月 23 日,与 Xcode7 Beta 版和 Swift 2 兼容
在 Swift 中读 C 指针
下面这个 Objective-C 方法会返回一个int指针,或者说 C 术语里面的
(int *):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @interface PointerBridge : NSObject { int count; } - (int *) getCountPtr; @end @implementation PointerBridge - (instancetype) init { self = [super init]; if(self) { count = 23; } return self; } - (int *) getCountPtr { return &count; } @end |
PointerBridge类,它包含
getCountPtr方法,这个方法返回一个值为 23 的
int型内存地址。 这个
Int其实是
count的实例,它在构造方法
init中被赋值为 23 。
我把这段代码放在一个 Objective-C 的头文件中,然后把这个头文件 import 到我的桥接头文件(XXX-bridging-header.h)中,这样就可以在 Swift 中使用。然后我在 Swift 中创建一个名为
bridge的
PointerBridge实例,然后获得
getCountPtr()方法的返回值…
1 2 3 4 | let bridge = PointerBridge() let theInt = bridge.getCountPtr() print(theInt) print(theInt.memory) |
theInt检查它的类型,你会发现他的 Swift 类型是
UnsafeMutablePointer<Int32>。这是指向
Int型的指针,和
Int型不一样,它仅仅是指向它的指针。
如果运行这个程序然后执行这段 Swift 代码,我们会发现
theInt在命令行中输出类似 0x00007f8bdb508ef8 这样的内存地址,然后,然后我们会看到
memory成员变量输出的值 23 。访问指针指向的内存通常返回其底层指向的对象,在这个例子中就是原来的 32 位
int(在 Swift 中就是
Int32)
现在让 Objective-C 类支持设置
count的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1819 | @interface PointerBridge : NSObject { int count; } - (int *) getCountPtr; - (void) setCount:(int)newCount; @end @implementation PointerBridge - (instancetype) init { self = [super init]; if(self) { count = 23; } return self; } - (int *) getCountPtr { return &count; } - (void) setCount:(int)newCount { count = newCount; } @end |
setCount()方法来修改
count的值。因为
theInt是一个指针,所以通过
setCount修改
count也会更新
theInt.memory。别忘了内存地址是不会变的,变的是值。
也就是说,下面的代码会在命令行中打印数字 23, 然后打印数字 1000。
1 2 3 45 | let bridge = PointerBridge() let theInt = bridge.getCountPtr() print(theInt.memory) // 23 bridge.setCount(1000) print(theInt.memory) // 1000 |
.memory,有一条捷径就是把
.memory赋值给一个变量:
1 2 3 4 | let bridge = PointerBridge() let theInt = bridge.getCountPtr() let countVal = theInt.memory print(countVal) // 23 |
setCount()方法修改
count的值,问题出现了:
1 2 3 45 | let bridge = PointerBridge() let theInt = bridge.getCountPtr() let countVal = theInt.memory print(countVal) // 23 |
countVal是通过值(value)来赋值的。赋值的时候值(value)就是23,所以
countVal有它自己的内存地址,这个地址永久地保存了 23 这个值,所以已经失去了指针的特性。
countVal现在只是一个普通的
Int32型。
在 Swift 中创建 C 指针
如果我们想要做和上面相反的事情呢?不是用Int型来给
count赋值,而是传入一个指针呢?
我们假设在 Objective-C 的代码中有如下的一个方法:
1 2 3 | - (void) setCountPtr:(int *)newCountPtr { count = *newCountPtr; } |
newCountPtr重新赋值给 count,但在 Swift 开发中你确实会碰到这样一些需要传入指针的场景。用这么作的方式只是为了向你展示如何在 Swift 中创建指针类型,然后传入到 Objective-C 的方法中。
你可能会简单的认为只要使用一个类似 & 的引用操作符就可以传入
Int值,就像你在 C 中所做的那样。在 Objective-C 中你可以这样写:
1 2 | int mcount = 500; [self setCountPtr:&mcount]; |
count的值更新为 500。然而在 Swift 中,通过自动补全你会发现它更复杂(而且更冗长)。它需要传入一个
UnsafeMutablePointer<Int32>类型的
newCountPtr变量。
我知道这个类型很恶心,而且它看起来确实很复杂。但是,事实上它相当简单,特别是在你了解 Obj-C 中的指针的情况下。如果要创建一个
UnsafeMutablePointer<Int32>类型的对象,我们只需要调用构造方法,这个构造方法唯一需要传入的参数就是指针的大小(你应该知道 C 的指针是不存储类型的,所以它也不会存储大小的信息)
1 2 3 45 | let bridge = PointerBridge() let theInt = bridge.getCountPtr() print(theInt.memory) // 23 let newIntPtr = UnsafeMutablePointer<Int32>.alloc(1) newIntPtr.memory = 100 bridge.setCountPtr(newIntPtr) print(theInt.memory) // 100 |
UnsafeMutablePointer<Int32>构造方法传入的参数就是需要分配空间的对象的个数,所以我们传入 1 即可,因为我们只需要一个
Int32对象 。然后,只需要把我们之前对
memory所做的事情反过来,我们就可以为我们新建的指针赋值。最终,我们只需要简单滴把
newIntPtr传入到
setCountrPtr方法中,再把之前
theInt指针的值打印出来,我们就会发现它的值已经被更新为 100。
总结
UnsafeMutablePointer<T>类型的兄弟类型
UnsafePointer<T>从根本上说只是 C 指针的一个抽象。你可以把它们看作 Swift 的可选类型,这样更容易理解。它们不是直接等于一个确切的值,而是在一个确切的值上面做了一层抽象。它们的类型是泛型,这样就可以允许其使用其他的值,而不单单是
Int32。比如你需要传入一个
Float对象那么你可能需要
UnsafeMutablePointer<Float>。
重点是:你不是把一个
Int强转 为
UnsafeMutablePointer<Int>,因为指针不是简单地一个
Int值。所以,如果需要创建一个新的对象,你需要调用构造方法
UnsafeMutablePointer<Int>(count: Int)。
在本文之后我们会继续深入研究函数指针的一些细节,然后学习如何利用这些特性的优势去更好地与 C 和 Objective-C 的 API 进行交互。一定要注册我们的 Newsletter ,这样你才不会错过这些精彩的内容!
相关文章推荐
- A PAPER LIST FOR OBJECT DETECTION IN VIDEOS
- [Object C]_[初级]_[文件修改创建时间和修改时间]
- IOS开发基础Object-C(07)—OC内存管理(1)-retain和release
- xcode 7种使用coredata遇到 Class not found, using default NSManagedObject instead.问题
- extend&super&Object&Abstract
- Xamarin演练:绑定一个Objective-C类库
- Object类
- NSObject--block
- [论文笔记4]Robust Object Detection via soft cascade
- Objective-C之代理设计模式小实例
- objective-c基础教程——学习小结
- Windows下的Objective-C集成开发环境(IDE)
- 关联(objc_setAssociatedObject、objc_getAssociatedObject)
- objective-C protocol协议
- Windows 下使用 GNUstep 编译并运行 Objective-C 程序
- Objective-C学习笔记之block
- 【Objective-C】Windows下Objective-C开发环境配置
- Odoo8查询产品时提示"maximum recursion depth exceeded while calling a Python object"
- Objective-C Blocks Quiz
- 如何使用swfobject(中文版)