天天看點

Swift 方法排程探究

1.方法排程分類

1.1 方法排程可以分為靜态排程(static dispatch)和動态排程,動态排程從實作上來說又可以劃分為虛拟表也就是Table dispatch比如c++和消息分發message dispatch比如OC用到的就是消息分發機制。

1.2靜态排程和動态排程各有各的好處

1.2.1編譯器可以對靜态排程的方法進行包括inline内聯函數在内的編譯期優化以及加快程式運作速度。

1.2.2動态排程可以實作面向對象程式設計三大特性之一的多态。即在運作時根據調用方去找具體的方法實作。

2.swift中的方法排程

2.1swift中根據方法所定義的位置來講會用到上面所說的三種方法排程方法。

2.1.1 比如struct,enum等值類型中的定義的方法(不包含繼承自某個協定中的方法),定義為final類型的class中的方法以及private方法 ,這些都是靜态排程。

2.1.2 class類型中的方法,protocol中聲明的方法 為table dispatch

2.1.3 nsobject子類中@objc dynamic 方法為message dispatch

3swift中table dispatch的實作

Swift 方法排程探究

3.1 如上圖所看到的,class類型的在其中繼資料類型中會引用一個函數指針類型的數組,在對象進行方法調用時去改數組中去查找相對應的方法實作。

Swift 方法排程探究
Swift 方法排程探究
Swift 方法排程探究

3.2 protocol-Witness-Table,Existential Container,value-Witness-Table

3.2.1protocol-Witness-table作用和valuetable一樣,在每一個struct中都會引用這樣一張表,進行相應方法查詢。

3.2.2Existential Container 如上圖所示,由于每一個結構體類型的記憶體大小各不相同,為了保障數組的位元組對齊。使用Existential Container的方式把每個struct對象存入數組中,Existential Container前三個valueBuffer用于存放struct的資料,剩餘兩個分别引用自己的vwt和pwt。需要注意的是如果結構體的屬性過多(big value),那麼會開辟一塊堆區記憶體,然後valuebuffer對這塊記憶體進行引用。為了管理Existential Container 存放的值,是以引用value-Witness-Table建立記憶體,初始化以及記憶體銷毀。

protocol drawable {
    
    func draw()
}
struct point:drawable {
    
    func draw() {

        print("draw a point")
    }
    
    var x,y:Float;
}

struct line:drawable {
    
    var x1,y1,x2,y2:Float;
    
    func draw() {
        
         print("draw a line")
    }
  
  
}

 var draws = [drawable]()
        
        draws.append(point(x:10,y:10))
        
        draws.append(line(x1: 10, y1: 10, x2: 20, y2: 20))
        
        for temp in draws {
            
            temp.draw()
            
            let size =   MemoryLayout<drawable>.size(ofValue: temp)
            
            print("\(type(of: temp))----\(size)") //輸出40
        }