web-dev-qa-db-ja.com

Objective-Cで定数を作成する最良の方法は何ですか

私は学習目的でRedditクライアントを作成しています。定数を含むファイルが必要です。 Reddit-Prefix.pchファイルにファイルをインポートして、すべてのファイルで定数を使用できるようにすることを考えていました。 それは物事を行うのに良い方法ですか?また、私は研究を行って、定数を作成するためのいくつかの方法を見つけましたが、どれを使用するのかわかりません:

  • #defineマクロ
  • const
  • static const
  • extern const
  • enum

だから、どの方法が好ましい方法ですか?慣習とは何ですか?「依存する」ことは知っていますが、私の質問はより具体的には:これらのソリューションのそれぞれのユースケースは何ですか?

また、extern constを使用する場合、ファイルをインポートする必要がありますか、それともファイルをインポートせずに定数をグローバルに使用できますか?

論理的に結論付けることができることの1つは、カスタムエラードメインのようなものを定義するとき、enumが最良の選択であるということです(実際に正しいでしょうか?)。しかし、他の人はどうですか?

154
Robert Audi

最初の質問は、定数にどのスコープを持たせるかです。これは実際には2つの質問です。

  • これらの定数は単一のクラスに固有のものですか、それともアプリケーション全体で使用する意味がありますか?
  • クラス固有である場合、クラスのクライアントが使用するのですか、それともクラス内でのみ使用するのですか?

それらが単一のクラスに固有で内部的なものである場合は、次のように、.mファイルの先頭でstatic constとして宣言します。

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

単一のクラスに関係しているが、他のクラスでパブリック/使用する必要がある場合は、ヘッダーでexternとして宣言し、.mで定義します。

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

グローバルにする必要がある場合は、ヘッダーで宣言し、対応するモジュールで、特にこれらの定数に定義します。

これらをさまざまなレベルのグローバルなレベルの異なる定数と、単に一緒に属さない異なるグローバル定数とを組み合わせて一致させることができます。欲しいです。

なぜ#defineではありませんか?

古い答えは「マクロには型情報がありません」ですが、今日のコンパイラーは、リテラル(マクロの拡張対象)と変数のすべての型チェックを行うのが非常に賢明です。

最新の答えは、デバッガーがマクロを認識しないためです。 MyThingNotificationKeyがマクロの場合、デバッガーコマンドで[myThing addObserver:self forKey:MyThingNotificationKey]と言うことはできません。デバッガーは、変数の場合にのみそれについて知ることができます。

なぜenumではありませんか?

まあ、rmaddyはコメントで私にそれを打ちました:enumは整数定数しか定義できません。シリアルID番号、ビットマスク、4バイトコードなど。

これらの目的には、enumが最適であり、絶対に使用する必要があります。 (さらに良いのは、 NS_ENUMおよびNS_OPTIONSマクロ を使用してください。)他のものについては、must何か他のものを使用してください。 enumは整数以外は何もしません。

その他の質問

Reddit-Prefix.pchファイルにファイルをインポートして、すべてのファイルで定数を使用できるようにすることを考えていました。それは物事を行う良い方法ですか?

おそらく無害ですが、おそらく過剰です。必要な場所に定数ヘッダーをインポートします。

これらの各ソリューションのユースケースは何ですか?

  • #define:かなり制限されています。正直なところ、これを定数に使用する正当な理由があるかどうかはわかりません。
  • const:ローカル定数に最適です。また、ヘッダーで宣言して現在定義しているものにこれを使用する必要があります。
  • static const:ファイル固有(またはクラス固有)の定数に最適です。
  • extern const:ヘッダーの定数をエクスポートするときにこれを使用する必要があります。

また、extern constを使用する場合、ファイルをインポートする必要がありますか、それともファイルをインポートせずに定数をグローバルに使用できますか?

ファイルを使用する各ファイルまたはプレフィックスヘッダーのいずれかにファイルをインポートする必要があります。

380
Peter Hosey

FOUNDATION_EXPORT

基礎で定義され、C、C++、およびWin32の互換形式にコンパイルされるため、externよりも少し互換性のあるFOUNDATION_EXPORTの使用を検討してください。

NSObjCRuntime.hで定義されている

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
8
Steve Moser