14

次の例に示されている奇妙な動作に悩まされています。

NSMutableArray *a1 = [[NSMutableArray alloc] init]; // fine
NSMutableArray *a2 = [NSMutableArray array];        // fine, too

// compiler reports incompatible pointer types; good:
NSMutableArray *a3 = [[NSArray alloc] init]; 

// compiler says nothing and is happy to assign this!
NSMutableArray *a4 = [NSArray array]; 

とクラスの両方のinitarrayメソッドは を返します。ただし、これらのメソッドを呼び出したときの動作はまったく同じではありません。clang を使用すると、変数に空を喜んで割り当てることができます。NSArrayNSMutableArrayidNSArrayNSMutableArray

clangは、ファミリを含む一部のメソッドの戻り値の型を に自動的に変更するinitinstancetypeため、コンパイル時に を[[NSArray alloc] init]返すものNSArray *と を返すものを判別できることがわかりましたNSMutableArray *。しかし、このチェックは単にメソッドでは機能しませんarray

なんで?私の最後の例のような行は、少なくとも警告を生成するべきではありませんか? これらすべてのメソッドが return として宣言されていないのはなぜinstancetypeですか? 今後変わるのでしょうか?


アップデート

朗報: iOS 7 の時点で、[NSArray array]が返さinstancetypeれるため、a4上記への代入でも警告が発生します。arrayWithContentsOfFile:orのような他のメソッドはarrayWithContentsOfURL依然として を返しidますが…</p>

4

2 に答える 2

10

しかし、このチェックは単に配列メソッドでは機能しません。なんで?

リンクしたドキュメントが説明しているように、認識された関連結果タイプ-arrayが得られないためです。ObjC は非常に動的です。コンパイラは の結果の型を保証できません。命名規則が明確に定義されているため (例: 、、など) 、一部のメソッドではその仮定が行われます。したがって、この実装は単に命名規則に頼っています。+array+alloc-init+new-self

コンパイラは、予期しない領域でいくつかの命名規則も検証します。

@implementation NSArray (DEMO)

- (id)initStr
{
    return [NSString new]; // << warning. RE: init prefix
}

@end

私の最後の例のような行は、少なくとも警告を生成するべきではありませんか? これらすべてのメソッドがインスタンス型を返すと宣言されていないのはなぜですか? 今後変わるのでしょうか?

instancetype約1年前に導入されました(見た目から)。一部の API は数十年前に作成されました。(正しく使用すれば) 既存のコードの多くの問題点を指摘できるためいずれ実現すると思います。もちろん、これらの変更は既存のビルドを破壊します (ここでも、適切な場所で宣言されていれば、通常は適切な修正が行われます)。

そのため、バグを報告し、ツールとライブラリの更新に数年かかります。変更が行われたと仮定すると、おそらく OS のメジャー アップデートで行われるでしょう。

しばらくの間、オプションの警告として有効にした方がよいでしょう (システム ヘッダーの場合)。もちろん、新しい API 用の古いコンパイラとの下位互換性を維持しながら、これを採用することもできます。

また、この変更は単純な typedef によって非常に簡単に後付けできます (以前のコンパイラは と のセマンティックの違いを理解していませんでしたid) 。instancetypetypedef の 1 つの問題は、それがグローバルな宣言であることです。コンパイラは、グローバルな typedef を追加してキーワードをシミュレートする手間をかけずに、単語/修飾子/属性を特定のスコープに制限できます。Apple の GCC は をサポートinstancetypeしない可能性があるため、Apple の GCC にそれを導入する論理的な方法は のグローバルtypedefidある可能性があり、一部の人々にとっては問題を引き起こす可能性があります (そのルートが使用された場合、セマンティックな利点はありません)。過去に Apple によって同様の重大な変更が行われたことに注意してください。

于 2013-03-06T14:40:41.263 に答える
3

結局のところ、間違った配列型を使用することが許されているだけでなくid . たとえば、これは警告なしでコンパイルされます。

NSMutableArray *a4 = [NSDictionary dictionary]; 

これは、タイプ セーフをオプトアウトするために使用することの副作用であり、idお気づきのように、非推奨の動作であり、instancetype に置き換える必要があります (上記の方法で使用すると、互換性のない型の警告がスローされます)。

残念ながら、これはバグではありません。 instancetypeはかなり新しいキーワードであり、まだ広く採用されておらず、Apple のフレームワーク全体で使用を開始するのは大胆な動きです。次の SDK には常に希望があります。

于 2013-03-06T14:05:02.573 に答える