iOS学习开发手机移动程序开发iOS开发者进阶

Swift指针和托管

2020-01-16  本文已影响0人  __Mr_Xie__

前言

想必已经使用 Swift 语言进行开发的小伙伴们都享受到了这门语言在开发过程中带来的便利,确实作为苹果官方主推的编程语言,融合了主流编程语言的优点,旨在提高开发效率,已经开始逐步走上替代 OC 的道路了。然而不是事事尽如人意,Swift 语言也存在一些不足,其中最主要的问题有两个:

指针

Swift 中,指针都是以一个泛型结构体 UnsafePointer<T> 表示,遵从 Cocoa 一贯的设计原则,它是不可变的,与之对应的就是可变指针 UnsafeMutablePointer<T>。这两个泛型分别可以对应 C 语言中的常指针 const void * 和普通指针 void *。我们通常来说可以通过 & 操作从一个 Cocoa 类型T获取到其指针表示 UnsafePointer<T>,这一点和 C 语言基本一致,有一定的不同。最典型的就是在 Swift2.0 之前传递 NSError 的指针 NSErrorPointer

var error: NSError?
var possibleData =NSJSONSerialization.JSONObjectWithData(responseData,options:NSJSONReadingOptions.AllowFragments,error: &error) as? NSDictionary;
if let actualError = error {
    println("An Error Occurred: \\\\(actualError)")
}
else if let data = possibleData {
   // do something with the returned data
}

但是 Swift& 操作和 C 语言不同的一点是,Swift 不允许直接获取对象的指针,比如下面的代码就会编译不通过。

let a = NSData()
let b = &a //编译出错

指针的管理和其他对象的管理是不同的,其他的对象是 ARC 管理的,而指针需要我们手动地申请和释放内存,指针基本的使用步骤如下:

var p = UnsafePointer<NSData>.alloc(1)
let data = NSMutableData()
p.initialize(data)
p.destroy() //释放指向的对象 
p.dealloc(1) //释放指针申请的内存

托管

托管解决的问题同样是来自 C 语言,在 CocoaCore Fundation 框架就是封装的一套 C 语言 API。在Swift中使用Core Fundation,苹果提出了内存管理注释 annotated APIsUnmanaged<T> 泛型结构体结合的解决方案。

let bestFriendID = ABRecordID(...)
// Create Rule - retained
let addressBook: ABAddressBook = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()
// Get Rule - unretained
if let bestFriendRecord: ABRecord = ABAddressBookGetPersonWithRecordID(addressBook, bestFriendID)?.takeUnretainedValue() {
   // Create Rule (Copy) - retained
       if let name = ABRecordCopyCompositeName(bestFriendRecord)?.takeRetainedValue() as? String {
        //do something
       }
}

练习

相信各位小伙伴如果把下面这个 CF 函数搞明白了,也就弄懂了 Swift 的指针和托管,Let's do it!

public func CFStreamCreateBoundPair(alloc: CFAllocator!, _ readStream: UnsafeMutablePointer<Unmanaged<CFReadStream>?>, _ writeStream: UnsafeMutablePointer<Unmanaged<CFWriteStream>?>, _ transferBufferSize: CFIndex)

这个方法还是挺有用处的,官方文档也有提及,但是相关资料非常少,所以想搞明白怎么用的小伙伴继续往下看喔,只此一家!

  1. 首先我们一个个参数分析
  1. 之前说过,使用指针之前需要初始化,所以我们先初始化指针。我们根据函数也可以判断,我们不需要申请一段内存,所以只需要申请一个Unmanaged<CFReadStream>?大小的内存就好了。
let readStreamPointer = UnsafeMutablePointer<Unmanaged<CFReadStream>?>.alloc(1)
let writeStreamPointer = UnsafeMutablePointer<Unmanaged<CFWriteStream>?>.alloc(1)
  1. 由于我们的指针是可变的,memory 可以被赋值,所以调用方法 CFStreamCreateBoundPair 之后,memory 就被赋值为了创建的Unmanaged<CFReadStream>? 类型的非托管对象。我们可以通过 memory 取到这个非托管对象。根据 Create rules,我们应该使用 takeRetainedValue() 获取到 CFReadStream 类型的对象,这时候非托管对象已经把对象的管理权交由给了 SwiftARC 管理。NSStreamCFStream 之间是 toll free bridging
CFStreamCreateBoundPair(kCFAllocatorDefault, readStreamPointer,writeStreamPointer, Int(bufferSize) as CFIndex)
if let readStream = readStreamPointer.memory?.takeRetainedValue(),writeStream = writeStreamPointer.memory?.takeRetainedValue(){// create rules
    let rStream = readStream as NSInputStream
    let wStream = writeStream as NSOutputStream //toll free bridging
    //do something with rStream/wStream
}
  1. 释放指针申请的内存空间,与 alloc 对应的 delloc
readStreamPointer.dealloc(1)
writeStreamPointer.dealloc(1)

完整的代码如下:

let readStreamPointer = UnsafeMutablePointer<Unmanaged<CFReadStream>?>.alloc(1)
let writeStreamPointer = UnsafeMutablePointer<Unmanaged<CFWriteStream>?>.alloc(1)
CFStreamCreateBoundPair(kCFAllocatorDefault, readStreamPointer,writeStreamPointer, Int(bufferSize) as CFIndex)
if let readStream = readStreamPointer.memory?.takeRetainedValue(),writeStream = writeStreamPointer.memory?.takeRetainedValue(){// create rules
    let rStream = readStream as NSInputStream
    let wStream = writeStream as NSOutputStream //toll free bridging
    //do something with rStream/wStream
}
readStreamPointer.dealloc(1)
writeStreamPointer.dealloc(1)

总结

指针和托管在 Swift 语言的发展过程中起到了兼容和过渡的作用,相信随着 Swift 语言的发展,这类问题我们会越来越少遇到,开发效率也会越来越高。但是目前我们在开发过程中还是总会碰到这样的问题,如果这篇文章对你有帮助的话,点一个喜欢和关注就是对我最大的鼓励啦!

Author

如果你有什么建议,可以关注我的公众号:iOS开发者进阶,直接留言,留言必回。

转载

Swift指针和托管,你看我就够了

上一篇 下一篇

猜你喜欢

热点阅读