Swift3 Unsafe[Mutable]Pointer

这篇文章水准不高,可能因为我自己能力有限,英文水平也就这样,自己能看懂,可能存在误人子弟的可能性,所以如果有人有机会看到了这边文章就当是一个小白的入门级的笔记吧!如果需要更深入的了解请查看文末的参考链接

为了将我的PhotoCutter适配Swfit3一看到一大堆的Unsafe[Mutable]Pointer的错误就是脑壳疼!最头疼的事没有找到这方面的中文资料,只有自己来弄了,然后记录一下,现在项目还是用OC,一天不写就生疏,怕以后来自己又忘记了,然后自己纪录一下吧...

这里我先粗略地介绍:
1.我的理解:UnsafeMutablePointer其实就是UnsafePointer的可以变化的类型,但是UnsafePointer又不允许你去改变指针元素

2.Unsafe[Mutable]RawPointer:在swift3以前为Unsafe[Mutable]Pointer<Void>,也就是c中的void *

3.Unsafe[Mutable]BufferPointer表示一连串的数组指针

withUnsafePointer/withUnsafeMutablePointer

比如下面我用c的方式创建和销毁了一个int型的指针a:

int \*a = malloc(sizeof(int));
\*a = 10;
free(a)

假设在swift中var a:Int = 10,现在我们的目的是想创建一个指针a,我们需要将a转成*a,我们需要怎么做呢?这里可以用到withUnsafePointer/withUnsafeMutablePointer

这两个函数会以swift类型和一个block为参数,而这个目的指针就是这个block的参数。也就是说你想将某一个swift类型的参数转换为一个指针result,这个result就是你想获得的指针,也就是下面两个例子中的ptr,希望我这个描述没有把你绕晕!

这里我也以swift.org上面的socket例子来写吧!

var addrin = sockaddr_in()

创建UnsafeMutablePointer

withUnsafeMutablePointer(to: &addrin) { ptr in
    //ptr:UnsafeMutablePointer\<sockaddr_in>
}

创建UnsafePointer

withUnsafePointer(to: &addrin) { ptr in
    //ptr: UnsafePointer\<sockaddr_in>
}

withUnsafeBytes/withUnsafeMutableBytes

通过withUnsafeBytes/withUnsafeMutableBytes获得的bytes只能在在函数closure里面进行使用,这个函数只相对于Data类型来获取bytes使用!

func unsafebytes() {
    guard let data = ".".data(using: .ascii) else{ return }
    data.withUnsafeBytes { (byte:UnsafePointer<CChar>) -> Void in
        print(byte) 
    }
}
unsafebytes()

withMemoryRebound

我们可以使用withMemoryRebound函数,来将一个类型的指针转换为另外一个类型的指针,使用这个函数的时候也有一些需要注意点,在[UnsafeRawPointer Migration] (1)的介绍中说到:Conversion from UnsafePointer<T> to UnsafePointer<U> has been disallowed,所以只能将UnsafePointer<Int>转换为UnsafeMutablePointer<UInt8>.

UnsafePointer<Int> -> UnsafeMutablePointer<UInt8>

var a = 10
withUnsafePointer(to: &a) { a_pt in
    a_pt.withMemoryRebound(to: UInt8.self, capacity: 1, { a_pt_uint8 in
        //a_pt_uint8:UnsafeMutablePointer           
    })
}

具体的使用场景:
在使用socket的时候需要bind或者connect的时候
这个函数的具体使用场景在[UnsafeRawPointer Migration] (1)中也有提到。

sockaddr_in -> sockaddr

var addrin = sockaddr_in()
let sock = socket(PF_INET, SOCK_STREAM, 0)
let result = withUnsafePointer(to: &addrin) {
    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        connect(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
    }
}

assumingMemoryBound

UnsafeRawPointer转换为UnsafePointer<T>类型,也就是swift3之前的UnsafePointer<Void>UnsafePointer<T>

这个和前面提到的函数withMemoryRebound的区别就是:

assumingMemoryBound可以看成是withMemoryRebound的一个特例,即:
assumingMemoryBoundUnsafePointer<Void>UnsafePointer<T>
withMemoryReboundUnsafePointer<U>UnsafeMutablePointer<T>

代码示例:

let strPtr = UnsafeMutablePointer\<CFString>.allocate(capacity: 1)
let rawPtr = UnsafeRawPointer(strPtr)
let intPtr = rawPtr.assumingMemoryBound(to: Int.self)

bindMemory

绑定一个类型<T>到已经被分配的内存空间,返回一个绑定在self内存上UnsafePointer<T>的指针,需要注意的是这个函数是用于Unsafe[Mutable]RawPointer。

/// - Precondition: The memory is uninitialized.
/// - Postcondition: The memory is bound to 'T' starting at `self` continuing
///   through `self` + `count` * `MemoryLayout<T>.stride`
/// - Warning: Binding memory to a type is potentially undefined if the
///   memory is ever accessed as an unrelated type.
操作 内存状态 类型
rawptr = allocate() uninitialized None
tptr = rawptr.bindMemory(T) uninitialized bound to T
tptr.initialize() initialized bound to T

从上面的表格结合文档里面对于bindMemory的说明来看,我对于bindMemory的理解就是,使用函数之前这块内存空间是没有被初始化的,使用bindMemory的目的是将T绑定到self后面self + count * MemoryLayout<T>.stride长度的的这块内存空间上来。但是绑定上来并不代表初始化了,此时这个内存空间仍然是没有初始化的,所以最后需要调用函数initialize的函数来初始化!

用这个函数同样可以把void *的C类型转换为Swift的类型。关于Custom memory allocation
这个函数的使用可能会有问题...先上一段我自己理解的代码吧

let a = 100
let a_rawptr = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout\<Int>.size, alignedTo: MemoryLayout\<Int>.alignment)
let bind_rawptr = a_rawptr.bindMemory(to: Int.self, capacity: MemoryLayout\<Int>.stride)
bind_rawptr.initialize(to: a)

unsafeBitCast

返回一个翻译成某一特定类型的值!,这个会破坏Swift的类型系统

特别注意️:
不到万不得已不要使用这个函数

实战

PhotoCutter为了适配Swift3,这其中大部分和指针相关的东西需要适配,我开始看到这些也是懵逼的,根本不懂怎么改,只有自己去慢慢学。我的方法可能很差,就目前而言是适配了,下面贴上我的修改的代码吧!

Swift2.x

options = CFDictionaryCreate(kCFAllocatorDefault,
            UnsafeMutablePointer(UnsafePointer<Void>(keys)),
            UnsafeMutablePointer(UnsafePointer<Void>(values)),
            2,
            &kcKeysBack,
            &kcValuesBack)

Swift3.0

fileprivate func buffer<T>(to type:T.Type, source:[T]) -> UnsafeMutablePointer<UnsafeRawPointer?>{
    var buffer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: source.count)
    for idx in 0..<source.count {
        let m_ptr = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout<T>.size, alignedTo: MemoryLayout<T>.alignment)
        let bindptr = m_ptr.bindMemory(to: type, capacity: 1)
        bindptr.initialize(to: source[idx])
        let pty = UnsafeRawPointer(m_ptr)
        buffer.advanced(by: idx).pointee = pty
    }
    return buffer
}

调用:

let keys:[CFString] = [
            kCGImageSourceCreateThumbnailWithTransform,
            kCGImageSourceCreateThumbnailFromImageIfAbsent,
            kCGImageSourceThumbnailMaxPixelSize]
var keybuffer = buffer(to: CFString.self, source: keys)
/*
这之间做你的相关操作
*/
keybuffer.deallocate(capacity: keys.count)

到这里我对于swift3指针相关的东西,就告一段落了,文章写的很粗糙,望见谅,明天开始公司要求做持续化集成了,如果你看到这个而且想和我交流的话可以在博客上的微博和我取得联系,因为我是真的不懂博客。。。以后有时间会去学习一下前端相关的东西,练手项目应该就是我这个博客!

最后还是希望去看看C 语言指针 5 分钟教程


参考文献:

Use Swift With Cocoa
UnsafeRawPointer Migration Swift.org
Swift 3.0 Unsafe World
StackOverflow Question
Binding memory type
Swift 中的指针使用(这个是之前版本的介绍,就参考一下用unsafeBitCast,同时文章中提到的C 语言指针 5 分钟教程)
指针

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容