web-dev-qa-db-ja.com

Objective-Cの定数

私は Cocoa アプリケーションを開発しています、そして私は私の好みのためにキー名を保存する方法として定数NSStringsを使用しています。

必要に応じてキーを簡単に変更できるため、これは良い考えです。さらに、それは全体として「自分のデータを自分のロジックから切り離す」という概念です。

とにかく、これらの定数をアプリケーション全体に対して1回定義するのに良い方法はありますか?簡単でインテリジェントな方法があると確信していますが、今のところ私のクラスはそれらが使用するものを再定義するだけです。

991
Allyn

次のようなヘッダーファイルを作成してください。

// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.

(コードがC/C++混在環境または他のプラットフォームで使用されない場合は、FOUNDATION_EXPORTの代わりにexternを使用できます)

このファイルは、定数を使用する各ファイル、またはプロジェクトのプリコンパイル済みヘッダーに含めることができます。

これらの定数は、.mファイルで次のように定義します。

// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

アプリケーション/フレームワークのターゲットにConstants.mを追加して、それが最終製品にリンクされるようにする必要があります。

#define'd定数の代わりに文字列定数を使用する利点は、文字列比較(stringInstance == MyFirstConstant)よりもはるかに速い(さらに読みやすく、IMO)ポインタ比較([stringInstance isEqualToString:MyFirstConstant])を使用して等価性をテストできることです。

1269
Barry Wark

最も簡単な方法:

// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"

もっと良い方法:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";

2つ目の利点の1つは、定数の値を変更してもプログラム全体が再構築されないことです。

274
Andrew Grant

言及する1つのこともあります。非大域定数が必要な場合は、staticキーワードを使用してください。

// In your *.m file
static NSString * const kNSStringConst = @"const value";

staticキーワードのため、このconstはファイルの外からは見えません。


@QuinnTaylorによるわずかな修正静的変数はコンパイル単位内に表示されます。通常、これは(この例のように)単一の.mファイルですが、コンパイル後にリンカエラーが発生するため、他の場所に含まれているヘッダーで宣言すると噛み付くことがあります

187
kompozer

受け入れられた(そして正しい)答えは、「この[Constants.h]ファイルをプロジェクトのプリコンパイル済みヘッダーに含めることができます」と述べています。

初心者として、これ以上説明することなくこれを行うのは困難でした-方法は次のとおりです:YourAppNameHere-Prefix.pchファイル(これはXcodeのプリコンパイル済みヘッダーのデフォルト名です)で、Constants.hをインポートします#ifdef __OBJC__ブロック

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "Constants.h"
#endif

また、Constants.hファイルとConstants.mファイルには、受け入れられた回答に記載されているものを除いて、他に絶対に何も含めるべきではないことに注意してください。 (インターフェイスまたは実装なし)。

118
Victor Van Hee

私は一般的にBarry WarkとRahul Guptaによって投稿された方法を使っています。

ただし、.hファイルと.mファイルの両方で同じ単語を繰り返すのは好きではありません。次の例では、行は両方のファイルでほぼ同じです。

// file.h
extern NSString* const MyConst;

//file.m
NSString* const MyConst = @"Lorem ipsum";

したがって、私がしたいのは、Cプリプロセッサ機構を使用することです。例を通して説明しましょう。

マクロSTR_CONST(name, value)を定義するヘッダファイルがあります。

// StringConsts.h
#ifdef SYNTHESIZE_CONSTS
# define STR_CONST(name, value) NSString* const name = @ value
#else
# define STR_CONST(name, value) extern NSString* const name
#endif

定数を定義したい.h/.mペアで、次のようにします。

// myfile.h
#import <StringConsts.h>

STR_CONST(MyConst, "Lorem Ipsum");
STR_CONST(MyOtherConst, "Hello world");

// myfile.m
#define SYNTHESIZE_CONSTS
#import "myfile.h"

et voila、私は.hファイルだけで定数に関するすべての情報を持っています。

50
Krizz

私は自分の好みのために使われる定数NSStringsを宣言するための専用のヘッダを持っています。

extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;

それから付随する.mファイルでそれらを宣言します。

NSString * const PPRememberMusicList = @"Remember Music List";
NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
NSString * const PPAfterPlayingMusic = @"After playing music";
NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";

このアプローチは私には役に立ちました。

編集:これは、文字列が複数のファイルで使用されている場合に最も効果的です。 1つのファイルでしか使用されていない場合は、文字列を使用する.mファイル内で#define kNSStringConstant @"Constant NSString"を実行するだけで済みます。

26
MaddTheSane

@Krizzの提案を少し修正したもので、定数ヘッダーファイルをPCHに含める場合には正しく機能します。これはかなり普通のことです。オリジナルはPCHにインポートされるので、それは.mファイルにそれをリロードしないでしょう、そしてそれ故あなたはシンボルを得ず、そしてリンカは不幸です。

ただし、次のように変更すると機能します。少し複雑ですが、うまくいきます。

あなたは 3 files、定数の定義を持っている.hファイル、.hファイルと.mファイルをそれぞれ必要とします、私はそれぞれConstantList.hConstants.hConstants.mを使います。 Constants.hの内容は単に次のとおりです。

// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"

Constants.mファイルは次のようになります。

// Constants.m
#ifdef STR_CONST
    #undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"

最後に、ConstantList.hファイルには実際の宣言が含まれていて、それがすべてです。

// ConstantList.h
STR_CONST(kMyConstant, "Value");
…

注意すべき点がいくつかあります。

  1. マクロを使用するには、.mファイルの の後に #undefingしてマクロを再定義する必要がありました。

  2. これが正しく動作し、コンパイラが以前にプリコンパイルされた値を認識しないようにするためにも、#includeの代わりに#importを使用する必要がありました。

  3. これは、値が変更されたときはいつでもあなたのPCH(そしておそらくプロジェクト全体)の再コンパイルを必要とするでしょう。それらが通常のように分離(そして複製)されている場合はそうではありません。

誰かに役立つことを願っています。

25
Scott Little
// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";
14
rahul gupta

Abizerが言ったように、あなたはそれをPCHファイルに入れることができます。それほど汚れていないもう1つの方法は、すべてのキーのインクルードファイルを作成してから、それをキーを使用しているファイルに含めるか、PCHに含めることです。それらを独自のインクルードファイルに含めることで、少なくともこれらすべての定数を探して定義するための場所が1つ得られます。

12
Grant Limberg

大域定数のようなものが必要な場合は、簡単で汚い方法は、定数宣言をpchファイルに入れることです。

11
Abizern

クラスメソッドを使ってみてください。

+(NSString*)theMainTitle
{
    return @"Hello World";
}

私は時々それを使います。

8
groumpf

名前空間定数が好きなら、あなたは構造体を利用することができます 金曜日Q&A 2011-08-19:名前空間定数および関数

// in the header
extern const struct MANotifyingArrayNotificationsStruct
{
    NSString *didAddObject;
    NSString *didChangeObject;
    NSString *didRemoveObject;
} MANotifyingArrayNotifications;

// in the implementation
const struct MANotifyingArrayNotificationsStruct MANotifyingArrayNotifications = {
    .didAddObject = @"didAddObject",
    .didChangeObject = @"didChangeObject",
    .didRemoveObject = @"didRemoveObject"
};
8
onmyway133

シングルトンクラスを使用しているので、テストのために必要に応じてクラスをモックして定数を変更することができます。定数クラスは次のようになります。

#import <Foundation/Foundation.h>

@interface iCode_Framework : NSObject

@property (readonly, nonatomic) unsigned int iBufCapacity;
@property (readonly, nonatomic) unsigned int iPort;
@property (readonly, nonatomic) NSString * urlStr;

@end

#import "iCode_Framework.h"

static iCode_Framework * instance;

@implementation iCode_Framework

@dynamic iBufCapacity;
@dynamic iPort;
@dynamic urlStr;

- (unsigned int)iBufCapacity
{
    return 1024u;
};

- (unsigned int)iPort
{
    return 1978u;
};

- (NSString *)urlStr
{
    return @"localhost";
};

+ (void)initialize
{
    if (!instance) {
        instance = [[super allocWithZone:NULL] init];
    }
}

+ (id)allocWithZone:(NSZone * const)notUsed
{
    return instance;
}

@end

そしてこれは次のように使われます(定数cの省略形の使い方に注意してください - 毎回[[Constants alloc] init]をタイプする手間が省けます):

#import "iCode_FrameworkTests.h"
#import "iCode_Framework.h"

static iCode_Framework * c; // Shorthand

@implementation iCode_FrameworkTests

+ (void)initialize
{
    c  = [[iCode_Framework alloc] init]; // Used like normal class; easy to mock!
}

- (void)testSingleton
{
    STAssertNotNil(c, nil);
    STAssertEqualObjects(c, [iCode_Framework alloc], nil);
    STAssertEquals(c.iBufCapacity, 1024u, nil);
}

@end
7
Howard Lovatt

Objective CからこのNSString.newLine;のようなものを呼び出し、それを静的定数にしたい場合は、Swiftで次のようなものを作成できます。

public extension NSString {
    @objc public static let newLine = "\n"
}

そして、あなたは読みやすい定数定義を持っていて、スタイルは型の文脈に拘束されている間あなたが選択した型の中から利用できます。

0
Renetik