Swift相关程序员iOS 开发

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

2016-06-07  本文已影响1728人  文兴

想必已经使用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) //释放指针申请的内存

搞清楚了上面的基本使用,你已经能够处理在Swift中遇到的大部分和指针相关的情况了。如果还有这里没有提及到的用法,你肯定能在猫神 onevcat 的Swift 中的指针使用中找到答案~

托管

托管解决的问题同样是来自C语言,在Cocoa中Core Fundation框架就是封装的一套C语言API。如果在OC中使用Core Fundation,可以参考这篇文章:说说Core Foundation。在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)

这个方法的使用场景在我的上一篇文章iOS图库大视频上传有提到过,还是挺有用处的,官方文档也有提及,但是相关资料非常少,所以想搞明白怎么用的小伙伴继续往下看喔,只此一家!

  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类型的对象,这时候非托管对象已经把对象的管理权交由给了Swift的ARC管理。NSStream和CFStream之间是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语言的发展,这类问题我们会越来越少遇到,开发效率也会越来越高。但是目前我们在开发过程中还是总会碰到这样的问题,如果这篇文章对你有帮助的话,点一个喜欢和关注就是对我最大的鼓励啦!

上一篇 下一篇

猜你喜欢

热点阅读