3

Objective-C 言語に慣れるために iOS 開発者ガイドを読んでいますが、現在、 のようなオブジェクトの作成に関連するコンテナ リテラルと添字表記のトピックについて少し混乱していますNSDictionary

NSDictionaryKey-Value エンコーディング (dictionaryWithObjects:forKeys:およびdictionaryWithObjectsAndKeys:、またはそれらに対応する初期化子)を含むオブジェクトを作成する方法がいくつかあることを理解しています。ソースリンク。

私の理解では、これを行うには主に 2 つの方法があり、次にコンテナー リテラルを使用する別の方法があります。

NSDictionary *myDictionary = @{
   @"name" : NSUserName(),
   @"date" : [NSDate date],
   @"processInfo" : [NSProcessInfo processInfo]
};

最適な使用方法はどれですか? 前の 2 つの手法よりも Container Literal 手法を使用する利点はありますか?それとも、プログラマーにとって単に便利なことなのでしょうか?

配列などをコーディングするためのもう 1 つの簡単な方法でもあるという印象を受けています。これは本当ですか、それともここに欠けているものがありますか? これらのテクニックは個人的な好みの問題ですか?

4

3 に答える 3

12

これまでに投稿された他の回答には同意しません。ほとんどの場合、コンストラクターを使用するよりも、新しいコンテナーリテラル構文を使用する方が適切です。これらはコードの正確性に役立ち、互換性について心配することはそれほどありません。

コードの正確さ

コンテナリテラルは確かにシンタックスシュガーですが、具体的には「安全な」コンストラクタメソッド+[NSArray arrayWithObjects:count:]とにマップされます+NSDictionary dictionaryWithObjects:forKeys:count:。これらのメソッドのいずれかを直接使用して配列または辞書を作成するのはそれほど便利ではないため、多くのプログラマーは、を使用する方が簡単だと感じていarrayWithObjects:ますdictionaryWithObjectsAndKeys:。ただし、後者のメソッドには厄介な落とし穴があります。引数リストはで終了する必要があるため、オブジェクトを渡す予定の場所をnil渡すと、予期しない配列/辞書の内容が表示される可能性があります。nil

たとえば、モデルオブジェクトの1つのプロパティをマッピングするディクショナリを設定しているとします(おそらく、JSONとして送信しますか?):

NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
    person.name, @"name", person.title, @"title", person.address, @"address", 
    nil];

このコードがPersonnotitleが設定されているに遭遇した場合、結果の辞書には@"address"キーとその値がありません。データベース内の一部の人がアドレスを失っている理由を追跡するのに何時間も費やすことができます(そして、上記のコードを見て、なぜそれが機能しないのか疑問に思って髪を引き裂いてください、私はそれをすぐに設定しています!)。私たちの多くは持っています。

対照的に、次のような文字通りの形式を使用する場合:

NSDictionary *dictionary = @{
    @"name": person.name, @"title": person.title, @"address": person.address };

これは次のように拡張されます。

id objects[] = { person.name, person.title, person.address };
id keys[] = { @"name", @"title", @"address" };
NSUInteger count = sizeof(objects) / sizeof(keys);
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
                                                       forKeys:keys
                                                         count:count];                          

また、またはがを返す場合person.nameperson.titleこのnilメソッドは、不要なデータをサイレントに作成する代わりに、例外をスローします。(どちらの方法でも、コードでnilタイトルを処理する方法を決定する必要がありますが、この方法で問題をより早く見つけることができます。)そして確かに、同等の構文糖衣を使用する代わりに、この「より安全な」フォームを自分で書くことができます。しかしdictionaryWithObjectsAndKeys:、それが短いので、あなたはただ書く習慣に頼らないと確信していますか?

互換性

コンテナリテラル(さらに言えば、数値リテラルとボックス式)によって生成されたコードは新しいAPIを使用しないため、Xcode 4.4以降(またはClang 3.1以降)でコンパイルして、任意のバージョンのFoundationにデプロイできます。ただし、ソースコードが古いコンパイラやGNUStepでも使用される場合は、互換性を考慮する必要があります。(GNUStepはClangでもうまくいくように聞こえますが。)

そして、それは質問の一部ではありませんが、関連する主題に関するものであるため、新しいオブジェクトの添え字構文についても同じことが「一種の」真実です。これは、Mac OS X10.6およびiOS6.0でのみ定義されている新しいメソッドを使用します...しかし、これらのメソッドはによって提供されlibarcliteます。(ご存知のとおり、ARCコードをiOS4.3またはMacOS X 10.6にデプロイしようとするとリンクされるライブラリ-もはやARCだけではありません!)したがって、必要なのはヘッダーでそれらを宣言することだけです。まだ行っていない場合はARCLiteを使用して、問題ありません。

于 2012-09-23T21:09:12.593 に答える
2

「最善の方法」はありません。特定のユース ケースに最適な方を使用してください。たとえば、アプリを移植可能にしたい場合 (つまり、Foundation のみを必要とし UIKit を必要としないロジックは、Mac OS X や GNUstep を使用した Linux などの他のプラットフォームでも実行できます)、リテラル構文の使用を避けます。非常にポータブルではありません。iOS でのみ動作させる必要がある場合は、それらを使用してください。便利だからです。

また、これらの表記は単なる構文糖衣です。つまり、メソッド名にマッピングされているため (私の知る限り、質問で言及した 2 つのメソッドに正確に対応しています)、パフォーマンス、動作に影響を与えません。アルゴリズムなど

はい、ご想像のとおりです。同じことが新しい添え字構文にも当てはまります。NSArray の場合は、 を呼び出します- objectAtSubscriptedIndex:

于 2012-09-21T18:26:50.297 に答える
1

GNUstep と clang を使用して GNU/Linux で使用できます。私の場合、ほとんどの場合、GNUstep はすべてのバージョンの gcc よりも clang でうまく動作します。(申し訳ありませんが、他の回答を編集する必要があります。これは初めてです)

于 2012-09-22T16:50:01.787 に答える