SWIFT-なぜFinalを使うのですか?


こんにちは.ジェゼロです.
今日はFinalについてお話しします
私はネット講座を聴いていた時に初めてこのFinalに触れたのですが、当時先生が引き継がないクラスの前にFinalキーワードを付けたほうがいいと言っていたので、何の考えもなく使っていました.なぜいきなりFinalを使うのがなぜ良いのか知りたいので調べてみましょう
💡 FinalとPrivateを使用するとパフォーマンスが向上するのはなぜですか?

理由はReducing Dynamic Dispatch!!


Dispatchは、どのメソッドを呼び出すかを決定するプロセスです.
Dispatchのタイプ
  • Static Dispatch
  • コンパイル時にどのような方法を使用するかは明確な
  • である.
  • Dynamic Dispatch
  • の実行時には、どのメソッドを実行するかを決定し、コンパイル時には、どの関数を実行するか分からない.
  • SWIFTでは、各クラスにvtableがあり、参照時に関数を呼び出すため、対応するオーバーヘッド
  • が発生する.
  • v table?? →仮想メソッドテーブル、仮想メソッドテーブル、メソッドオーバーライド率に基づいて、実行時(実行時)にどのメソッドを実行するかを決定する動的派遣をサポートするプログラミング言語で使用されるメカニズム(関数ポインタで配列されたもの).
  • 💡 Static VS Dynamic Dispatch

    // Static Dispatch
    struct HelloStruct {
      func printHello() {
        print("hello")
      }
    }
    let helloStruct = HelloStruct()
    helloStruct.printHello()
    structはValue Typeなので、他の場所から引き継ぐことはありません.したがって、コンパイル時にhelloStruct.printHello()呼び出しは常にHelloStruckのprintHelloを呼び出すため、コンパイル時に決定されたStatic Dispatchとして実行されます.また,Value Typeでは拡張も静的Dispatchとして動作する.
    // Dynamic Dispatch
    class HelloClass {
      func printHello() {
        print("hello")
      }
    }
    
    class HelloOtherClass: HelloClass { }
    
    let helloClass: HelloClass = HelloOtherClass()
    helloClass.printHello()
    classはReference Typeで、他の場所から引き継ぐことができます.コンパイル時に、どのオブジェクトから呼び出された呼び出し方法が正確に分からない.したがって、コンパイラは、実行時点でvテーブルを問合せ、メソッドがどのインスタンスで実行されるかを判断するために参照フォーマットに設定します.これがダイナミックディスパッチです.

    💡 Increasing Performance by Reducing Dynamic Dispatch


    swiftは、スーパークラスから複数のメソッドまたはプロパティを上書きできます.これは、プログラムが実行時に間接呼び出し(アドレス呼び出し関数)&間接アクセス(間接アクセス)によって、どのメソッドまたは属性を呼び出すかを決定することを意味する.これを動的派遣と呼び,この間接的な使い方を使うたびにオーバーヘッドが発生する.これにより、静的Dispatchを使用してパフォーマンスを向上させることができます.
  • 継承、キーワード
  • を上書き不要なクラス、メソッド、およびプログラムに貼り付ける
    finalを追加すると、クラスは継承されません.メソッドまたはpropertyに追加すると、サブクラスで上書きできないため、静的Dispatchとして実行されます.
    final class Human {
        var name: String = ""
        func sayHello() {
            print("Hello Human!")
        }
    }
     
    class Teacher: Human { }    // error! Inheritance from a final class 'Human'
  • のアクセスが現在のファイルに制限されている場合、プライベートキー
  • が貼り付けられる.
    privateキーワードを貼り付けると、参照できる場所はブロックに制限されます.
    したがって、コンパイラは、プライベートキーが参照できる場所で上書きされているかどうかを判断します.また,上書きできる箇所がなければ自分でfinalキーワードを導出し,Static Dispatchとして操作する.
    class Human {
        private var name: String = "" // Dynamic Dispatch
        private var alias: String = "" // Static Dispatch
        var age: Int = 0
        
        class Sodeul: Human {
            override var name: String {
                didSet {
                    print("이름 바꼈다!")
                }
            }
        }
    }
  • Wholeモジュールを使用して
  • を最適化
    WMO?? →モジュール全体をブロックにコンパイルし、内部レベルが上書きされているかどうかを推定し、上書きされていない場合は内部にfinalを貼り付けます.
    デフォルトでは、SWIFTコンパイルモジュール内の各ファイル.すなわち、コンパイル時にクラスが継承されているかどうかを確認する場合は、他のファイルが継承されているクラスがある可能性があるためfinalを推定できません.ただし、WMOに設定すると、モジュール全体がチェック・コンパイルされ、最終的には継承されていないクラスが内部に貼り付けられ、静的Dispatchになります.これは、SWIFTクラスのデフォルトアクセス制御が内部にあるためかもしれません.
    Openキーを貼り付けた場合は、外部モジュールからアクセスすることもできます.
    この場合、WMOは依然として動的Dispatchである

    の最後の部分


    後でクラスプラスFinalを継承しないで、その他のクラスは引用しないプログラムあるいは方法はprivateと宣言する習慣を身につけます.
    ありがとうございます.😊
    いつでもご健康のご指導をお待ちしております