Swift -03:方法調(diào)用和指針

1.方法調(diào)用

對于結構體中的?法都是靜態(tài)調(diào)?(直接調(diào)?)郭脂,那對于類?的 class 中的?法那?我們類中聲明的?法 是通過 V-table 來進?調(diào)度的澈歉。

1.1結構體方法調(diào)用

struct MyStruct {
    func method1()  {
        print("method1")
    }
    func method2()  {
        print("method2")
    }
}
let myStruct = MyStruct()
myStruct.method1()

我們看斷點


image.png

1.2類實例方法調(diào)用

我們定義如下類

class PWTeacher {
    func method1()  {
        print("method1")
    }
    func method2()  {
        print("method2")
    }
    func method3()  {
        print("method3")
    }
}

查看sil文件

sil_vtable PWTeacher {
  #PWTeacher.method1: (PWTeacher) -> () -> () : @main.PWTeacher.method1() -> () // PWTeacher.method1()
  #PWTeacher.method2: (PWTeacher) -> () -> () : @main.PWTeacher.method2() -> () // PWTeacher.method2()
  #PWTeacher.method3: (PWTeacher) -> () -> () : @main.PWTeacher.method3() -> () // PWTeacher.method3()
  #PWTeacher.init!allocator: (PWTeacher.Type) -> () -> PWTeacher : @main.PWTeacher.__allocating_init() -> main.PWTeacher    // PWTeacher.__allocating_init()
  #PWTeacher.deinit!deallocator: @main.PWTeacher.__deallocating_deinit  // PWTeacher.__deallocating_deinit
}

我們創(chuàng)建實例展鸡,并調(diào)用方法,通過斷點看調(diào)用

let t = PWTeacher()
t.method1()
t.method2()
t.method3()
image.png

通過匯編調(diào)試埃难,我們可以看出在結構體調(diào)用方法時莹弊,是直接call地址,而類實例調(diào)用方法時涡尘,則是通過偏移找到方法在vtable的位置箱硕,然后再call調(diào)用。我們可以看出method1悟衩,method2剧罩,method3,在偏移時座泳,之間相差8字節(jié)惠昔。
extension的調(diào)用方式呢

extension PWTeacher {
    func method4()  {
        print("method4")
    }
}
let t = PWTeacher()
t.method4()

我們通過匯編調(diào)試,看一下


image.png

extension中的方法調(diào)用和struct中的方法調(diào)用是一樣的都是直接調(diào)用挑势。

1.3.方法關鍵字

final 關鍵字修飾方法

我們調(diào)用final修飾的方法镇防,從匯編看出是直接調(diào)用,從sil文件可以看到vtable文件沒有被final修飾的方法潮饱。

@objc修飾方法

調(diào)用還是在vtable中通過偏移找到函數(shù)指針進行調(diào)用的
在sil中我們可以看到


image.png

經(jīng)過@objc修飾的函數(shù)在sil中會生成兩個函數(shù)来氧,一個供swift調(diào)用,一個供OC調(diào)用香拉,但是供OC函數(shù)內(nèi)還是調(diào)用供的swift調(diào)用的函數(shù)啦扬。

swfit類繼承NSObject,

我們在oc中可以訪問,方法屬性如果添加@objc凫碌,oc內(nèi)也可以訪問

class PWTeacher :NSObject{
   @objc  var age:Int = 10
    @objc func teachMethod(){
        print("teachMethod")
    }
}

我們可以在項目-Swift.h文件中看到

SWIFT_CLASS("_TtC10OCAndSwift9PWTeacher")
@interface PWTeacher : NSObject
@property (nonatomic) NSInteger age;
- (void)teachMethod;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
image.png

dynamic關鍵字

class PWTeacher {
  dynamic func method1()  {
        print("method2")
    }

}
let t = PWTeacher()
t.method1()

swift調(diào)用的時候扑毡,還是調(diào)用vtable方法表,

dynamic加@objc關鍵字

class PWTeacher {
@objc  dynamic func method1()  {
        print("method2")
    }
}
let t = PWTeacher()
t.method1()

我們看匯編


image.png

經(jīng)過objc dynamic修飾的盛险,方法調(diào)用objc_msgSend

dynamic加@_dynamicReplacement

class PWTeacher {
dynamic func method()  {
        print("method")
    }

}
extension PWTeacher {

    @_dynamicReplacement(for:method)
    func method1()  {
        print("method1")

        
    }
}
let t = PWTeacher()
t.method()
t.method1()

打印結果

method1
method1

調(diào)用method時瞄摊,實質(zhì)是調(diào)用的method1。調(diào)用method1和原先不變苦掘。

1.4.補充arm64下的匯編指令

blr ; 帶返回的跳轉(zhuǎn)指令换帜,跳轉(zhuǎn)到指令后邊跟隨寄存器中保存的地址
mov: 將某?寄存器的值復制到另?寄存器(只能?于寄存器與寄存器或者寄存器 與常量之 間傳值,不能?于內(nèi)存地址)鹤啡,如: 6 mov x1, x0 將寄存器 x0 的值復制到寄存器 x1 中
ldr: 將內(nèi)存中的值讀取到寄存器中惯驼,如: 9 ldr x0, [x1, x2] 將寄存器 x1 和寄存器 x2 相加作為地址,取該內(nèi)存 地址的值放?寄存器 x0 中
str : 將寄存器中的值寫?到內(nèi)存中揉忘,如: 12 str x0, [x0, x8] 跳座, 將寄存器 x0的值保存到內(nèi)存[x0 + x8]處
bl: 跳轉(zhuǎn)到某地址

2.指針

原始指針的使用

let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
for i in 0..<4 {
    p.advanced(by: i*8).storeBytes(of: i+1, as: Int.self)
}
for i in 0..<4 {
let value =  p.load(fromByteOffset: i*8, as: Int.self)
    print(value)
}
p.deallocate()

allocate:分配32字節(jié)的內(nèi)存大小
advanced:代表當前p前進的步長,對于RawPointer來說泣矛,我們需要移動的是

withUnsafePointer的使用

var age = 18
age = withUnsafePointer(to: &age){
    ptr in
    ptr.pointee + 12
}
print(age)

能正常打印
如果我們想在內(nèi)部修改ptr的值則可以使用withUnsafeMutablePointer

var age = 18
withUnsafeMutablePointer(to: &age){
    ptr in
    ptr.pointee += 12
}
print(age)

打印結果是30

UnsafeMutablePointer的使用

var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1);
ptr.initialize(to: 20)
ptr.deinitialize(count: 1)
ptr.deallocate()
print(ptr.pointee)

allocate和deallocate疲眷,initialize和deinitialize是成對出現(xiàn)的
結構體指針的使用

struct PWPerson {
    var age = 18
    var height = 180
}
var ptr = UnsafeMutablePointer<PWPerson>.allocate(capacity: 2)
ptr.initialize(to: PWPerson())
ptr.advanced(by: 1).initialize(to: PWPerson(age: 20, height: 190))
//方法1訪問
print(ptr[0])
print(ptr[1])
//方法2訪問
print(ptr.pointee)
print((ptr+1).pointee)
//方法3訪問
print(ptr.pointee)
print(ptr.successor().pointee)

ptr.deinitialize(count: 2)
ptr.deallocate()

在advanced中因為我們知道類型所以知道一次要移動的字節(jié)數(shù),所以我們在這里寫1您朽,2狂丝,3等步數(shù),
而UnsafeMutableRawPointer移動的是字節(jié)數(shù)哗总,因為不知道步長是多少几颜。

swift實例轉(zhuǎn)化成結構體

class PWTeacher {
    var age:Int = 18
    
}
struct HeapObject {
    var kind:UnsafeRawPointer
    var strongRef:UInt32
    var unownedRed :UInt32

}
struct lg_swift_class {
    var kind: UnsafeRawPointer
    var superClass: UnsafeRawPointer
    var cachedata1: UnsafeRawPointer
    var cachedata2: UnsafeRawPointer
    var data: UnsafeRawPointer
    var flags: UInt32
    var instanceAddressOffset: UInt32
    var instanceSize: UInt32
    var flinstanceAlignMask: UInt16
    var reserved: UInt16
    var classSize: UInt32
    var classAddressOffset: UInt32
    var description: UnsafeRawPointer

}

var t = PWTeacher()
//Unmanaged 類似于OC和CF所有權的轉(zhuǎn)換
let ptr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
//ptr獲得的指針類型為UnsafeMutableRawPointer
//通過bindMemory,從RawPointer轉(zhuǎn)換成UnsafeMutablePointer讯屈,
let heapPoiner = ptr.bindMemory(to: HeapObject.self, capacity: 1)
let metaPtr = heapPoiner.pointee.kind.bindMemory(to: lg_swift_class.self, capacity: 1)

print(metaPtr.pointee)

總結:
Unmanaged.passUnretained是把一個UnsafePointer(UnsafeMutablePointer)類型的指針轉(zhuǎn)成UnsafeMutableRawPointer
ptr.bindMemory:是UnsafeMutableRawPointer指針綁定為UnsafePointer(UnsafeMutablePointer)指針蛋哭,如果ptr已經(jīng)是UnsafePointer(UnsafeMutablePointer)則重新綁定
bindMemory(to: Capacity:) : 更改內(nèi)存綁定的類型,如果之前沒有綁定涮母,那么就是?次綁定谆趾;如果綁 定過了,會被重新綁定為該類型

UnsafePointer類型的轉(zhuǎn)換 UnsafePointer<(Int,Int)>轉(zhuǎn)化成UnsafePointer<Int>

var tul = (10,12)
func test(ptr:UnsafePointer<Int>){
    print(ptr.pointee)
}
withUnsafePointer(to: &tul) {
    (tulPtr:UnsafePointer<(Int,Int)>) in
    test(ptr: UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int.self))
}

assumingMemoryBound: 假定內(nèi)存綁定叛本,這?是告訴編譯器:哥們我就是這種類型沪蓬,你不要檢查我 了

withMemoryRebound UnsafePointer<Int>轉(zhuǎn)化成UnsafePointer<UInt64 >

var age = 10
func test(ptr:UnsafePointer<UInt64>) {
    print(ptr.pointee)
}
withUnsafePointer(to: &age) { (ptr:UnsafePointer<Int>)  in
    test(ptr: ptr.withMemoryRebound(to: UInt64.self, capacity: 1){$0})
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市来候,隨后出現(xiàn)的幾起案子跷叉,更是在濱河造成了極大的恐慌,老刑警劉巖营搅,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件云挟,死亡現(xiàn)場離奇詭異,居然都是意外死亡转质,警方通過查閱死者的電腦和手機植锉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峭拘,“玉大人俊庇,你說我怎么就攤上這事〖δ樱” “怎么了辉饱?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拣展。 經(jīng)常有香客問我彭沼,道長,這世上最難降的妖魔是什么备埃? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任姓惑,我火速辦了婚禮褐奴,結果婚禮上,老公的妹妹穿的比我還像新娘于毙。我一直安慰自己敦冬,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布唯沮。 她就那樣靜靜地躺著脖旱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪介蛉。 梳的紋絲不亂的頭發(fā)上萌庆,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音币旧,去河邊找鬼践险。 笑死,一個胖子當著我的面吹牛吹菱,可吹牛的內(nèi)容都是我干的捏境。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼毁葱,長吁一口氣:“原來是場噩夢啊……” “哼垫言!你這毒婦竟也來了?” 一聲冷哼從身側響起倾剿,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤筷频,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后前痘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凛捏,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年芹缔,在試婚紗的時候發(fā)現(xiàn)自己被綠了坯癣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡最欠,死狀恐怖示罗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芝硬,我是刑警寧澤蚜点,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站拌阴,受9級特大地震影響绍绘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一陪拘、第九天 我趴在偏房一處隱蔽的房頂上張望厂镇。 院中可真熱鬧,春花似錦左刽、人聲如沸捺信。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽残黑。三九已至馍佑,卻和暖如春斋否,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拭荤。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工茵臭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舅世。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓萤捆,卻偏偏與公主長得像誉尖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容