Swift指针

指针分类:

  • raw pointer:未指定数据类型的指针(原生指针)
  • typed pointer:指定数据类型的指针

表示方式:

raw pointer 在swift中的表示是UnsafeRawPointer

typed pointer在swift中的表示是UnsafePointer<T>,是一个泛型

Swift对照Objective-C,指针对应的关系:

Swift Objective-C 说明
UnsafePointer<T> const T * 指针和指向的内容都是不可变的
UnsafeMutablePointer<T> T * 指针和指向的内容均是可变的
UnsafeRawPointer const void * 指针指向未知的类型
UnsafeMutableRawPointer void * 指针指向尾椎的类型(可以修改)
原生指针的使用(RawPointer):
//指针内存需要手动管理

let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)

for i in 0..<4 {
    //advanced:步长
    //storebytes:写入内存
    p.advanced(by: i * 8).storeBytes(of: i, as: Int.self)
}

for i in 0..<4 {
    let value = p.load(fromByteOffset: i * 8, as: Int.self)
    print("index\(i),value:\(value)")
}

p.deallocate()

打印结果:

index0,value:0
index1,value:1
index2,value:2
index3,value:3
Program ended with exit code: 0

内容补充:在看Swift源码中查看UnsafeMutableRawPointer的过程中会有builtin

//builtin(标准模块) -->在编译的过程中会匹配LLVM里面的类型和方法,在当前编译过程当中,减少编译时的内存负担

创建类型指针:
方式一:
var age = 10
let p = withUnsafePointer(to: &age) { $0 }
方式二:
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1)

ptr.initialize(to: age)

ptr.deinitialize(count: 1)

ptr.deallocate()

知识补充:单一表达式
例子:

//ptr in return ptr :单一表达式,可以直接使用ptr来表示,也可以直接使用$0来表示
//方式一:
{ ptr in return ptr }
方式二:
{ ptr }
方式三:
{ $0 }
创建泛型指针:
struct LGTeacher {
    var age = 10
    var height = 1.85
}

var t = LGTeacher()

let ptr = UnsafeMutablePointer<LGTeacher>.allocate(capacity: 2)

ptr.initialize(to: LGTeacher())

ptr.advanced(by: 1).initialize(to: LGTeacher(age: 20, height: 1.75))

print(ptr[0])

print(ptr[1])

print(ptr.pointee)

print((ptr + 1).pointee)

print(ptr.successor().pointee)

ptr.deinitialize(count: 2)

ptr.deallocate()

打印结果:

LGTeacher(age: 10, height: 1.85)
LGTeacher(age: 20, height: 1.75)
LGTeacher(age: 10, height: 1.85)
LGTeacher(age: 20, height: 1.75)
LGTeacher(age: 20, height: 1.75)
Program ended with exit code: 0

知识补充:successor()

print(ptr.successor().pointee) 与 print((ptr + 1).pointee) 结果是一致的,本质上successor()这个方法就是向前移动8字节

实战一:将将变量t绑定到结构图HeapObject内存中

思路:

1、获取实例变量的内存地址(指针)
2、RawPointer-->重新绑定到heapObject内存指针

代码实现:

struct HeapObject {
    var kind: UnsafeRawPointer
    var strongRef: UInt32
    var unownedRef: UInt32
}

class LGTeacher {
    var age = 18
}

var t = LGTeacher()

//1、获取实例变量的内存地址(指针)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

//2、RawPointer-->重新绑定到heapObject内存指针
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)

print(heapObject.pointee)

输出结果:

HeapObject(kind: 0x0000000100008168, strongRef: 3, unownedRef: 0)
Program ended with exit code: 0

知识补充:

1、Unmanaged:所有权的转换
提供两个方法:
passRetained(引用计数+1,获取指针)
passUnretained(引用计数不+1,只获取指针)

2、bindMemory:指针重定向

实战二:将HeapObject中kind变量绑定到lg_swift_class

思路:

1、获取实例变量的内存地址(指针)
2、将指针重新绑定到lg_swift_class类内存指针

代码:

struct HeapObject {
    var kind: UnsafeRawPointer
    var strongRef: UInt32
    var unownedRef: UInt32
}

struct lg_swift_class {
    var kind: UnsafeRawPointer
    var superClass: UnsafeRawPointer
    var cacheData1: UnsafeRawPointer
    var cacheData2: UnsafeRawPointer
    var data: UnsafeRawPointer
    var falgs: UInt32
    var instanceAddressOffset: UInt32
    var instanceSize: UInt32
    var finstanceAlignMaskags: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressOffset: UInt32
    var description: UnsafeRawPointer
}

class LGTeacher {
    var age = 18
}

var t = LGTeacher()

//1、获取实例变量的内存地址(指针)
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

//2、RawPointer-->重新绑定到lg_swift_class内存指针
let heapObject = ptr.bindMemory(to: HeapObject.self, capacity: 1)

let metaPtr = heapObject.pointee.kind.bindMemory(to: lg_swift_class.self, capacity: 1)

print(metaPtr.pointee)

输出结果:

lg_swift_class(kind: 0x0000000100008140, superClass: 0x00007fff889888f8, cacheData1: 0x00007fff20206af0, cacheData2: 0x0000802000000000, data: 0x0000000100776562, falgs: 2, instanceAddressOffset: 0, instanceSize: 24, finstanceAlignMaskags: 7, reserved: 0, classSize: 136, classAddressOffset: 16, description: 0x0000000100003c3c)
Program ended with exit code: 0

说明:

lg_swift_class(kind: 0x0000000100008140, superClass: 0x00007fff889888f8, cacheData1: 0x00007fff20206af0, cacheData2: 0x0000802000000000, data: 0x0000000100776562, falgs: 2, instanceAddressOffset: 0, instanceSize: 24, finstanceAlignMaskags: 7, reserved: 0, classSize: 136, classAddressOffset: 16, description: 0x0000000100003c3c)
按照打印出来的结果来看,显示了具体内存地址的大小,与给定的数据类型相同

扩展:xx类指针怎么转换成元类指针,使用bindMemory,原理同上

实战三:assumingMemoryBound的使用:如果将元组tuple数据传递给testPointer方法

思路:

将tuple类型转换成UnsafePointer,然后使用assumingMemoryBound假定内存绑定,告诉编译器不要再次进行类型检查了

代码:

var tuple = (10, 20)

func testPointer(_ p: UnsafePointer<Int>) {
    print(p)
    print("end")
}

//assumingMemoryBound:假定内存绑定,告诉编译器tulPtr已经绑定过Int类型了,现在tulptr就是Int类型,不需要再次进行编译检查了
withUnsafePointer(to: &tuple) { (tulPtr: UnsafePointer<(Int, Int)>) in
    testPointer(UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self))
}

输出结果:

0x0000000100008058
(lldb) x/8g 0x0000000100008058
0x100008058: 0x000000000000000a 0x0000000000000014
0x100008068: 0x0000000000000000 0x0000000000000000
0x100008078: 0x0000000000000000 0x0000000000000000
0x100008088: 0x0000000000000000 0x0000000000000000
(lldb) 

根据格式化输出内存地址显示,tuple已经打印出来了,0xa是10,0x14是20

实战四:assumingMemoryBound的使用:如何获取结构体类型的指针

思路:

通过原生指针+偏移量的方式

代码:

struct HeapObject {
    var strongRef = 10
    var unownedRef = 20
}

func testPointer(_ p: UnsafePointer<Int>) {
    print(p)
    print("end")
}

var t = HeapObject()

withUnsafePointer(to: &t) { (ptr: UnsafePointer<HeapObject>) in
    //通过原生指针+内存偏移来获取
    let strongRefPtr = UnsafeRawPointer(ptr) + MemoryLayout<HeapObject>.offset(of: \HeapObject.strongRef)!
    testPointer(strongRefPtr.assumingMemoryBound(to: Int.self))
}

打印结果:

0x0000000100008078
(lldb) x/8g 0x0000000100008078
0x100008078: 0x000000000000000a 0x0000000000000014
0x100008088: 0x0000000100760680 0x0000000000000000
0x100008098: 0x0000000000000000 0x0000000000000000
0x1000080a8: 0x0000000000000000 0x0000000000000000
(lldb) 

根据格式或内存地址的结果说明:strongRef = 0xa =10,unownedRef = 0x14 = 20

总结:学习过程中一点积累,越来越好,加油

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

推荐阅读更多精彩内容

  • Swift 指针 前言 指针,作为编程中最重要的概念,一直存在于各大语言中,下面我们就来探索一下Swift中的指针...
    just东东阅读 681评论 0 3
  • 参考文献 Swift结构体指针操作官方文档Swift 和 C 不得不说的故事Swift指针和托管,你看我就够了 W...
    沉静BBQ阅读 8,001评论 1 25
  • 为了避免疏漏, 我从官方文档作了截图, 苹果官网文档1 , 文档2 本文概要 按照官方文档, 介绍Swift中的指...
    Lin__Chuan阅读 2,652评论 12 9
  • 前言 本篇文章主要讲解一下Swift中的指针,以及相关的应用场景,指针也是面试官经常问到的知识点,希望大家能够掌握...
    深圳_你要的昵称阅读 3,019评论 0 11
  • 本文系学习Swift中的指针操作详解的整理 默认情况下Swift是内存安全的,苹果官方不鼓励我们直接操作内存。但是...
    流火绯瞳阅读 14,967评论 2 28