web-dev-qa-db-ja.com

静的なNSStringの使用とインラインのNSString定数

Objective-Cでは、私の理解では、ディレクティブ "" foo "は定数NSStringを定義します。 @ "foo"を複数の場所で使用すると、同じ不変のNSStringオブジェクトが参照されます。

このコードスニペットが頻繁に表示されるのはなぜですか(たとえば、UITableViewCellの再利用):

static NSString *CellId = @"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellId];

ただの代わりに:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId"];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"CellId"];

私は、コンパイラがキャッチできない識別子名のタイプミスを防ぐためだと思います。しかし、もしそうなら、私は単にできませんでした:

#define kCellId @"CellId"

静的なNSString *ビットを避けますか?それとも何か不足していますか?

43
sickp

次の理由により、リテラルを定数に変換することをお勧めします。

  1. あなたが言ったように、それはタイプミスを避けるのに役立ちます
  2. 定数を変更したい場合は、1か所で変更するだけです

私は使うことを好む static const NSString*static NSString* constは、#defineよりも少し安全であるためです。本当に必要でない限り、私はプリプロセッサを避ける傾向があります。

60
Tom Dalling

私はここですべての答えが好きです。正しく宣言する方法の簡単な例はありません...だから...

定数を外部から見えるようにする場合(つまり、「グローバル」)...ヘッダーでそのように宣言します...

extern NSString *const MyTypoProneString;

そして、それを.mファイルで定義します[〜#〜] outside [〜#〜] any @implementation like ...

NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";

つまり、単にstatic const that IS LOCALをクラスの実装にしたい場合(または特定のメソッド!)...単に宣言するだけです。文字列[〜#〜] inside [〜#〜]実装(またはメソッド)...

static NSString *MavisBeacon = @"She's a freakin' idiot";

[〜#〜] edit [〜#〜]でも私はこれを行う方法を示します ...私はこのスタイルがであることをまだ確信していませんいずれにせよ途方もなく短く、単純で、反復性の低いSINGLE宣言よりも、アラ..

#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots"

#defineを使用してください...それらは煩わしさがはるかに少なくなります。プリプロセッサプレーヤーハッターに降ろさせないでください。

36
Alex Gray

静的変数constを作成する必要があります。

静的変数とマクロの違いの1つは、マクロがデバッガーでうまく機能しないことです。マクロもタイプセーフではありません。

[〜#〜] c [〜#〜] および C++ に対するstatic-var-vs-macroアドバイスの多くはObj-Cに適用されます。

9
outis

@"foo"を複数の場所で使用する場合、ランタイムがそれらに同じストレージを使用することは保証されておらず、コンパイルユニットまたはライブラリの境界を越えてそうであるとは限りません。
特にstatic NSString *string = @"foo"を使用します。特に、多くのリテラル文字列を使用します。

3
kiamlaluno

私は、コンパイラがキャッチできない識別子名のタイプミスを防ぐためだと思います。

正しい。これは、基本的な防御プログラミングの練習です。コンパイルされた結果(うまくいけば)はどちらの方法でも同じです。

しかし、もしそうなら、私は単にできませんでした:

#define kCellId @"CellId"

静的なNSString *ビットを避けますか?それとも何か不足していますか?

はい。ただし、kCellId記号は、少なくともコンパイルユニット内でグローバルに定義されます。静的変数を宣言すると、シンボルはそのブロックに対してローカルになります。

通常、プリプロセッサの定義ではなく、グローバル変数または静的変数として定義された文字列定数が表示されます。これにより、異なるコンパイルユニット間で単一の文字列インスタンスのみを処理することが保証されます。

2
Darren

だから、私は少し遅れてこれに入りますが、これはSOのC/C++の両方の領域でさまざまな方法で何度も尋ねられましたが、基本的にここに私のコメントの拡張バージョンがalex greyにあります:

文字列マクロに#defineを使用する必要があると思うときはいつでも、ほとんどの場合使用しないでください。その理由は、#defineマクロは基本的にはプリプロセッサーの正規表現に代わるものだからです。プリプロセッサが呼び出されたマクロを見ると、それはあなたが定義したものに置き換えられます。これはnew文字列リテラルが毎回メモリに割り当てられることを意味します。これは、セル再利用識別子などの場所では本当に悪いことです(そのため、AppleのUITableViewControllerのデフォルトコードではstaticを使用します)。

Eonilが述べたように、代わりにextern/static constを使用すると、すべての参照がメモリ内の1つの場所を指します。これは、はるかにメモリ効率がよく、パフォーマンスが高く、モバイルデバイスでは非常に重要です。

1
Matt S.