web-dev-qa-db-ja.com

静的文字列と#defineを使用する場合

いつ使用するのが最善かについて少し混乱しています。

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully";

の代わりに

#define AppQuitGracefullyKey    @"AppQuitGracefully"

私はCまたはC++についてこのような質問を見てきましたが、ここで異なるのは、これがObjective C専用であり、オブジェクトを利用し、iPhoneのようなデバイスでは、スタック、コードスペースまたはメモリの問題があるかもしれないことです私はまだ把握していません。

1つの使用法は次のとおりです。

appQuitGracefully =  [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];

それとも単にスタイルの問題ですか?

ありがとう。

45
mahboudz

静的を使用する場合、コンパイラはバイナリに文字列のコピーを1つだけ埋め込み、その文字列へのポインタを渡すだけで、バイナリがよりコンパクトになります。 #defineを使用すると、使用するたびにソースに保存された文字列の個別のコピーが存在します。定数文字列の合体は多くの重複を処理しますが、理由もなくリンカーをより難しくします。

60
cdespinosa

"static const" vs "#define" vs "enum" を参照してください。 staticの主な利点は、型の安全性です。

それ以外は、#defineアプローチは、静的変数では実行できないインライン文字列連結の柔軟性を導入します。

#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH@"/UIKit.framework"] load];

しかし、これはおそらく良いスタイルではありません:)。

14
kennytm

実際にはどちらもお勧めしません。代わりにexternを使用する必要があります。 Objective-cはすでに_FOUNDATION_EXPORT_を定義しています。これはexternよりも 移植性が高い であるため、グローバルNSStringインスタンスは次のようになります。

.h

_FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;
_

.m

_NSString * const AppQuitGracefullyKey = @"AppQuitGracefully";
_

通常、これらを宣言ファイル(_MyProjectDecl.h_など)に入れ、必要なときにいつでもインポートします。

これらのアプローチにはいくつかの違いがあります。

  • #defineには、タイプセーフではないなど、いくつかの欠点があります。そのための回避策(#define ((int)1)など)があることは事実ですが、ポイントは何ですか?また、このアプローチにはデバッグの欠点もあります。コンパイラは定数を好みます。 this の説明を参照してください。
  • staticグローバルは 宣言されたファイルで表示されます
  • externは、変数をすべてのファイルから見えるようにします。それは静的と対照的です。

Staticとexternは可視性が異なります。また、これらのアプローチのいずれも、コンパイラが String Interning を使用してそれを防ぐため、文字列を複製しません(_#define_でさえも)。 このNSHipsterの投稿 では、証拠が示されています:

_NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES
_

演算子_==_は、2つの変数が同じインスタンスを指している場合にのみYESを返します。そして、あなたが見ることができるように、それはします。

結論は、グローバル定数には_FOUNDATION_EXPORT_を使用します。デバッグしやすく、プロジェクト全体に表示されます。

4
André Fratelli

いくつかの検索( this 質問/回答)を行った後、文字列リテラル@"AppQuitGracefully"定数文字列を使用しているときはいつでも、いくつでも言うことは重要だと思います使用するたびにsameオブジェクトを指します。

だから私は(そして私が間違っているなら私に謝罪する)上の答えのこの文は間違っていると思う:If you use a #define, there will be a separate copy of the string stored in the source on each use.

4
Aleksa

USING #define:

識別子の値をデバッグすることはできません

#defineおよび他のマクロの処理はプリプロセッサの仕事です。最初にビルド/実行を押すと、ソースコードを前処理し、すべてのマクロ(記号#で始まる)で動作します。

あなたが作成したとします、

#define LanguageTypeEnglish @"en"

これをコードの2箇所で使用しました。

NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;

すべての場所で "LanguageTypeEnglish"@"en"に置き換えます。したがって、@"en"の2つのコピーが生成されます。すなわち

NSString *language = @"en";
NSString *languageCode = @"en";

このプロセスまで、コンパイラーは見えないことを忘れないでください。

すべてのマクロを前処理した後、コンパイラーが登場し、次のような入力コードを取得します。

NSString *language = @"en";
NSString *languageCode = @"en";

コンパイルします。

静的な使用:

スコープを尊重し、タイプセーフです。識別子の値をデバッグできます

コンパイルプロセス中にコンパイラが見つかった場合、

static NSString *LanguageTypeRussian = @"ru";

次に、同じ名前の変数が以前に保存されているかどうかを確認し、はいの場合はその変数のポインタのみを渡し、いいえの場合はその変数を作成してポインタを渡し、次回以降はそのポインタのみを渡します同じ。

したがって、静的を使用すると、スコープ内で変数のコピーが1つだけ生成されます。

3

ライブラリまたはフレームワークからNSStringシンボルをエクスポートする必要がある場合は、staticを使用します。私が使う #define簡単に変更できる多くの場所で文字列が必要な場合。とにかく、コンパイラとリンカが最適化を処理します。

3