NSWindowのcontentViewプロパティがid型の理由は何ですか?

Why is the contentView property of the NSWindow class of type id instead of NSView

これは意味がありません。なぜcontentViewは NSView 以外のサブクラスであるべきですか?

だから私の場合は、フレームにアクセスするために、このように入力しなければなりませんでした。

NSView *contentView = self.window.contentView;//returns an `id`
CGRect frame = contentView.frame

これの代わりに、コンパイラは好きではない:

CGRect frame =  self.window.contentView.frame;//This does not compile
4

3 答え

それはおそらく歴史的です。 Objective-Cは厳密な型指定をサポートしていますが、オブジェクトがクラスを気にせずに応答するメッセージを気にする「ダックタイピング」もサポートしていますすなわち、それがアヒルのように見え、それがアヒルのように突っ込むと、それはおそらくアヒルです)。すべてのオブジェクトポインタを id として入力して、どんなメッセージでも送ることができます。実際、受信者は受信するすべてのメッセージのメソッドを実装する必要はありません。メッセージを別のオブジェクトに転送することもできます。

OpenStepとCocoaの前身のGUIフレームワークであるApplication Kitでは、ほとんどすべてのオブジェクトがダックタイピングによって使用されていました。アプリケーションキットのバージョン3.2の Window の(部分的な)インターフェースです。

@interface Window : Responder
{
  NXRect frame;
  id contentView;
  id delegate;
  id firstResponder;
  id lastLeftHit;
  id lastRightHit;
  id counterpart;
  id fieldEditor;
  int winEventMask;
  int windowNum;
  float backgroundGray;
  //some bit masks indicating whether the window is visible, is key etc.
}
-contentView;
-setContentView:aView;
//more methods
@end

contentView ivarは id であると定義され、アクセサメソッド内のすべての型は暗黙的に id として定義されています -setContentView:はオブジェクトを返します。おそらく Window インスタンス self )。これが1990年代初めのObjective-Cコードの大半を示しています:アプリケーションキットはおそらく1990年代初めのObjective-Cコードの でした。

NSWindow was introduced in the first version of AppKit - the GUI framework in what became Cocoa, back in 1994. AppKit generally uses more strict type declarations than Application Kit did, but it's not rigidly observed. Indeed it may even be the case that AppKit's NSWindow contains code from Application Kit's Window, and that this contentView ivar was not updated in the change.

実際、Objective-C変数の型適合の厳格な要件は比較的最近のものです。厳密性の大部分は、プロパティ宣言(Cが存在し、キャストをサポートすることを除いて厳密に型指定されている)、またはオプションのメソッドを許可するプロトコルへの変更によって導入され、委譲オブジェクトを厳密に型指定することができます。

8
追加された
詳細な答えをありがとう。私は、キャストやコードの2行目で生きることができると思います。
追加された 著者 Besi,
私は、ますます静的なタイピングの使用が、より長い時間続くプロセスであると感じています。私が言語になったとき(2002年)、それはすでに遍在していました。 AppleのObjective-Cガイドは、できるだけ頻繁にその使用を推奨していました。事実、Appleが言語が許すほとんどすべてのケース(Appleがコンテナ、イニシャライザ、デリゲートを例外)で使用したように見えた。
追加された 著者 Nikolai Ruhe,
@NikolaiRhehe最初のモチベーターの1つは、ルートオブジェクトが既知のプロトコルに準拠しているとき(クライアントが境界を越えて respondsToSelector:呼び出しを送信し続ける必要がないため)しかし、明らかにのケースは変更されませんでした。これは、メソッドの戻り値の型として void を使用し始めたことを意味しています。
追加された 著者 user23743,

- [NSWindow contentView] id 型を持っているという事実は、おそらくココアとObjective-Cの初期の頃のものです。

とにかく:コンパイラの警告は、メッセージの送信に使用しているプロパティースタイルの構文の結果です。 Cocoa(Cocoa-Touchとは対照的に)ウィンドウでは、 contentView frame はクラスのプロパティではありません。つまり、通常のメッセージ送信構文を使用する必要があります。

CGRect frame = [[[self window] contentView] frame];

これはコンパイラの警告なしで動作します。

2
追加された
いいえ、エラーは、型 'id'にドット表記法のインターフェイスを有効にするための適切なメソッド宣言がないという事実から来ています。プロパティはドット表記を使用する必要はありません。私が望むなら [NSObject new] の代わりに NSObject.new を呼び出すことができます。
追加された 著者 Richard J. Ross III,
@Richard J.Ross III:ドット構文を使用して、タイプド変数 id にメッセージ(プロパティアクセサまたは非プロパティ)を送信することはできません。しかし、通常のメッセージ送信構文を使用して、任意のセレクタを送信することができます。
追加された 著者 Nikolai Ruhe,
@NikolaiRuhe:セレクタがまだ宣言されていない場合のARCモードは例外です。これは手動メモリ管理の警告でしたが、ARCとの間違いです。
追加された 著者 user23743,

これは動的タイピングのためのものです。 NSWindow は、送信されたセレクタに応答する場合、 contentView が実際には NSView であるかどうかを気にしません。ですから、このようにして理論的にはコンテンツを表示するために NSView から継承しない独自のクラスを作成することができ、コンパイラはチョークしません。

1
追加された
@NikolaiRuhe正しいですが、問題は暗黙のうちにidのドット表記を使用できるように変換することはできません。メソッドがIDのインタフェースで定義されていないためです。
追加された 著者 Richard J. Ross III,
setterのシグネチャは - (void)setContentView:(NSView *)view :(
追加された 著者 Nikolai Ruhe,
あなたが何を言おうとしているのか分かりません。 id はインターフェイスを宣言しません。とにかく、正しさのためにAppleのマニュアルに従って答えを編集する必要があります。 contentView NSView を返します。
追加された 著者 Nikolai Ruhe,