Swiftネイティブ基本クラスまたはNSObject


105

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

Cocoa / NSObject基本クラスなしでSwiftクラスを定義するのは正常ですか?私が心配しているのであれば、これは、メソッドのインターセプトやランタイムイントロスペクションなど、Objective-Cのダイナミズムの大部分を先導することを意味します。

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

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

しかし、一般的な95-5ルール(パフォーマンス向上の95%はコードの5%のチューニングから得られる)を考えると、強力な動的機能から始めて、必要に応じて強化することは理にかなっていますか?


関連:Swiftはアスペクト指向プログラミングをサポートしていますか?stackoverflow.com/a/24137487/404201
Jasper Blues

回答:


109

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

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

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

  • Objective-Cクラスですが、NSObject互換性のために実装されているメソッドはほんの一握りです
  • objc_msgSend()メソッドの呼び出しには使用しない(デフォルト)
  • メソッドの実装にObjective-Cランタイムメタデータを提供しない(デフォルト)

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

編集:

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

public dynamic func foobar() -> AnyObject {
}

1
Swiftはobjc_msgSendの代わりにどのようなディスパッチを使用しますか?静的ですか?
ビル

12
Swiftはobjc_msgSendディスパッチ、仮想テーブルディスパッチ、ダイレクトディスパッチ、またはインライン展開を使用できます。
グレッグパーカー

静的:1.1ns未満。vtable 1.1ns、msgSend 4.9ns。。(もちろんハードウェアに依存します)。。「純粋」なSwiftはシステムレベルのプログラミングに最適な言語になっていますが、アプリの場合、動的な機能を放棄することに消極的ですが、ガベージコレクション対ARCのようにコンパイラーに移行されれば幸いです。。。静的ディスパッチにより、マルチコアシステムでの分岐予測(およびパフォーマンス)が向上すると言われています。ほんと?
Jasper Blues、

「NSObjectのサブクラスではないSwiftクラスはObjective-Cクラスです」-記述されている場所へのリンクを提供できますか?
Matt S.

1
つまり、要約すると、Objective Cコードと通信する必要がある場合にのみ、SwiftでNSObjectをサブクラス化する必要がありますか?
MobileMon、

14

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

この例では、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に基づいています、コンパイラー 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のみに基づいていると思います!


1
情報をありがとう。
Jasper Blues

13

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

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

言語リファレンスから:

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

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

'super' members cannot be referenced in a root class

1
うん。プロジェクトのコンテキストでCocoaまたはCocoa Touchソースファイルを作成しようとすると、サブクラスを挿入するフォームにより、クラスを空白のままにしてクラスを作成できなくなります。スーパークラスは、作成後に削除できます。
Cezar

1
ありがとう。静的およびvtableディスパッチの使用は、システムプログラミングまたはパフォーマンスチューニングにとって意味があります。ネイティブのCocoaとの一貫性を保つために、私はダイナミックデフォルトであるべきだと思います。(誰かがそうでなければ私を納得させることができない限り、この質問)。
Jasper Blues

1

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

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


私にとっては、ダイナミズムをデフォルトにすることは理にかなっています(NSObjectを拡張し、「@ objc」装飾またはその他のアプローチを使用して)。基本クラスがない場合、Swiftはstatic / vtableディスパッチを優先しますが、パフォーマンスが向上しますが、ほとんどの場合、これは必要ありません。。(利益の90%はコードの10%のチューニングから得られます)。私の希望は、Objective-Cのダイナミズムとの整合性がオプトインではなくオプトアウトであることです。
Jasper Blues

言語の設計方法は、オプトインです。私たちが知る限り、将来的には、本来オブジェクトではないAPIがシステムに追加される可能性があります。中長期的には、既存のライブラリーを非objcコードに移行し、非objcコードを呼び出すobjcのシン互換性レイヤーを使用する場合もあります。私たちは知りません。educated guesses今から数年で作れると思います。しかし今のところ、それは大きな疑問符です。
アナログファイル

@JasperBlues私はほとんどの場合、ダイナミズムは必要ないことを主張します。デフォルトでパフォーマンスを得て、動的な動作にオプトインする必要があります。一人一人に私は推測します:)
ランス

@ランスうーん。多分。私はまだ心配しています:オブザーバー、AOP、テストモックフレームワーク、分析フレームワークなど。パフォーマンスについては、90%のゲインが10%のチューニングから得られるということです。。それが私の理論的根拠です-これらの10%のケースにオプトインします。AOPはiOSエンタープライズアプリにとって大きな問題になると思いますが、C ++のようにコンパイラツールを使用して行うこともできます。。確かにゲーム、科学計算、グラフィックスなどの開発者は、より多くのパフォーマンスを歓迎します:)
Jasper Blues

1

以下はAppleのSwift-eBookからコピーしたもので、質問に対する適切な回答を示しています。

基本クラスの定義

別のクラスから継承しないクラスは、基本クラスと呼ばれます。

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


参照

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251


-6

正常です。Swiftの設計目標を見てください。目標は、プログラミング問題の巨大なクラスをなくすことです。メソッドのスウィズリングは、おそらくSwiftで実行したいことの1つではありません。


3
メソッドのスウィズリングは、実行時にインターセプトパターンを実現する方法です。これの用途の1つは、アスペクト指向プログラミングの原則に従って、分野横断的な懸念を適用することです。Apple独自の通知、プロパティオブザーバー(組み込みから迅速)、コアデータはすべて、効果を上げるためにスウィズリングを使用します。。不格好な構文にもかかわらず、人々がObjective-Cに魅了されたことの1つはこのダイナミズムでした。これにより、インターセプトパターンが必要なときにいつでもエレガントなソリューションを簡単に提供できます。。実際、Objcには正式なAOPフレームワークはありませんでした。原材料がとても良かったからです。
Jasper Blues

これが現在行われている方法であることは、明日行われる方法であることを意味するものではありません。通知のとおり、プロパティオブザーバー、デリゲートなどは、ネイティブに提供されるか、提供される場合があります。言語は進化し、私たちはどちらの方向に行くのかわかりません。関数型プログラミングのサポートの点で多くを得ています。しかし、それは異常な方法で行われるため、どれだけ不足しているのかはわかりません。しかし、私たちが知る限り、彼らは変異を思いとどまらせ、純粋な関数型プログラミングを奨励する方向に向かっている可能性があります。UIの未来が反応する場合はどうなりますか?まだ知る方法がありません。
アナログファイル

1
はい。ただし、これらすべてはインターセプトに依存します。インターセプトは、コンパイル時(C ++)またはランタイム(Ruby、Objective-C、Java(asm、cglib、ApsectJなど))の2つの方法で実行できます。現代の言語は実行時にそれを行う傾向があります。Objective-Cは、古き良き時代にもかかわらず、現代の言語のように振る舞ったため、人々から愛されました。あなたが言うように、これを言語に焼き込めるほど良い(うまくいっていれば!)。。しかし今のところ、Objc / Foundationによって提供されるレガシーにフックすることができるので、NSObjectの拡張が今後数年にわたって日常のアプリの標準的なプラクティスになることを願っています。
Jasper Blues
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.