web-dev-qa-db-ja.com

SwiftネイティブベースクラスまたはNSObject

Swiftで isa swizzling をテストしましたが、NSObjectがスーパークラス(直接またはそれ以上)である場合、または '@objc'装飾を使用する場合にのみ機能することがわかりました。それ以外の場合は、C++などの静的およびvtable-dispatchスタイルに従います。

Cocoa/NSObject基本クラスなしでSwiftクラスを定義するのは正常ですか?私が懸念している場合、これはメソッドのインターセプトやランタイムのイントロスペクションなど、Objective-Cのダイナミズムの多くを先取りすることを意味しています。

動的な実行時の動作は、プロパティオブザーバー、コアデータ、 アスペクト指向プログラミング高次メッセージング 、分析およびロギングフレームワークなどの機能の中心にあります。

Objective-Cのメソッド呼び出しスタイルを使用すると、メソッド呼び出しに約20のマシンコードオペランドが追加されるため、特定の状況では(小さなボディを持つメソッドの多くのタイトな呼び出し )C++スタイルの静的およびvtableディスパッチのパフォーマンスが向上します。

しかし、一般的な95-5ルール()の95%のパフォーマンス向上は、コードの5%のチューニングによるものです)、開始する意味がありません強力な動的機能を使用して、必要に応じて強化しますか?

98
Jasper Blues

NSObjectのサブクラスであるSwiftクラス:

  • objective-Cクラス自体です
  • (ほとんどの)メソッドの呼び出しにobjc_msgSend()を使用します
  • メソッドの実装(のほとんど)にObjective-Cランタイムメタデータを提供する

NSObjectのサブクラスではないSwiftクラス:

  • objective-Cクラスですが、NSObjectとの互換性のためにほんの少数のメソッドのみを実装します
  • メソッドの呼び出しにobjc_msgSend()を使用しないでください(デフォルト)
  • メソッドの実装にObjective-Cランタイムメタデータを提供しない(デフォルト)

NSObjectをSwiftでサブクラス化すると、Objective-Cランタイムの柔軟性が得られますが、Objective-Cのパフォーマンスも向上します。 Objective-Cの柔軟性が必要ない場合は、NSObjectを避けるとパフォーマンスが向上します。

編集:

Xcode 6ベータ6では、動的属性が表示されます。これにより、メソッドが動的ディスパッチを使用する必要があることをSwiftに指示できるため、インターセプトがサポートされます。

public dynamic func foobar() -> AnyObject {
}
98
Greg Parker

また、NSObjectに基づいてSwiftクラスを作成すると、コーディングのバグを隠す可能性のある予期しない実行時の動作が見られることがわかりました。以下に例を示します。

do n't NSObjectをベースとするこの例では、コンパイラはtestIncorrect_CompilerShouldSpotでエラーを正しく見つけ、「... 'MyClass'は 'MirrorDisposition'に変換できません」と報告します。

class MyClass {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

NSObjectに基づくこの例では、コンパイラdoes n'tはtestIncorrect_CompilerShouldSpotでエラーを見つけます。

class myClass : NSObject {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

道徳は、本当にあなたがしなければならないNSObjectに基づいているだけだと思います!

14
Pete

言語リファレンスによると、クラスが標準ルートクラスをサブクラス化する必要はないため、必要に応じてスーパークラスを含めたり省略したりできます。

クラス宣言からスーパークラスを省略すると、暗黙の基本スーパークラスが割り当てられないことに注意してください。基本クラスを定義します。これは、独立したクラス階層のルートになります。

言語リファレンスから:

Swiftクラスは、ユニバーサル基本クラスから継承しません。スーパークラスを指定せずに定義したクラスは、自動的に構築するベースクラスになります。

スーパークラスのないクラス(つまり、基本クラス)からsuperを参照しようとすると、コンパイル時エラーが発生します。

'super' members cannot be referenced in a root class
12
Cezar

Swiftデータの大部分はobjcではないと考えています。 Objective Cインフラストラクチャと通信する必要がある部分のみが明示的にそのようにマークされます。

ランタイムイントロスペクションが言語にどの程度追加されるかはわかりません。メソッドのインターセプトは、メソッドで明示的に許可されている場合にのみ可能になる可能性があります。これは私の推測ですが、Apple内の言語設計者だけが本当にどこに向かっているのかを本当に知っています。

1
Analog File