web-dev-qa-db-ja.com

Objective-C静的クラスレベル変数

クラスFilmがあり、それぞれに一意のIDが格納されています。 C#では、Javaなど、静的int currentIDを定義でき、IDを設定するたびにcurrentIDを増やすことができ、変更はオブジェクトレベルではなくクラスレベルで発生します。これはObjective-Cで実行できますか?これに対する答えを見つけるのは非常に難しいことがわかりました。

141
Michael Allen

問題の説明

  1. ClassAにClassBクラス変数が必要です。
  2. Objective-Cをプログラミング言語として使用しています。
  3. Objective-Cは、C++のようにクラス変数をサポートしません。

1つの選択肢

Objective-C機能を使用してクラス変数の動作をシミュレートする

  1. ClassA.m内で静的変数を宣言/定義して、classAメソッド(およびclassA.m内に配置するすべてのもの)のみがアクセスできるようにします。

  2. NSObject初期化クラスメソッドを上書きして、静的変数をClassBのインスタンスで一度だけ初期化します。

  3. なぜNSObjectのinitializeメソッドを上書きする必要があるのでしょうか。 Appleこのメソッドに関するドキュメントには答えがあります:「ランタイムは、クラスまたはそれを継承するクラスが、 (クラスが使用されない場合、メソッドが呼び出されることはありません。)」.

  4. ClassAクラス/インスタンスメソッド内で静的変数を使用してください。

コードサンプル

ファイル:classA.m

static ClassB *classVariableName = nil;

@implementation ClassA

...

+(void) initialize
{
    if (! classVariableName)
        classVariableName = [[ClassB alloc] init];
}

+(void) classMethodName
{
    [classVariableName doSomething]; 
}

-(void) instanceMethodName
{
    [classVariableName doSomething]; 
}

...

@end

参照

  1. Objective-CとC++のアプローチを比較するクラス変数の説明
157
Albaregar

Xcode 8では、Obj-Cでクラスプロパティを定義できます。これは、Swiftの静的プロパティと相互運用するために追加されました。

Objective-CはSwiftタイププロパティと相互運用するクラスプロパティをサポートするようになりました。 @property(class)NSString * someStringProperty;として宣言されています。それらは決して合成されません。 (23891898)

ここに例があります

@interface YourClass : NSObject

@property (class, nonatomic, assign) NSInteger currentId;

@end

@implementation YourClass

static NSInteger _currentId = 0;

+ (NSInteger)currentId {
    return _currentId;
}

+ (void)setCurrentId:(NSInteger)newValue {
    _currentId = newValue;
}

@end

その後、次のようにアクセスできます。

YourClass.currentId = 1;
val = YourClass.currentId;

ここに非常に興味深いものがあります 説明的な投稿 この古い答えを編集するためのリファレンスとして使用しました。


2011 Answer:(これを使用しないでください、ひどいです)

本当にグローバル変数を本当に宣言したくない場合は、別のオプションがあります。多分あまりオーソドックスではありません:-)、しかし動作します。

+ (NSString*)testHolder:(NSString*)_test {
    static NSString *test;

    if(_test != nil) {
        if(test != nil)
            [test release];
        test = [_test retain];
    }

    // if(test == nil)
    //     test = @"Initialize the var here if you need to";

    return test;
}

したがって、値を取得する必要がある場合は、以下を呼び出してください。

NSString *testVal = [MyClass testHolder:nil]

そして、あなたがそれを設定したいとき:

[MyClass testHolder:testVal]

このpseudo-static-varをnilに設定できるようにしたい場合、次のようにtestHolderを宣言できます。

+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
    static NSString *test;

    if(shouldSet) {
        if(test != nil)
            [test release];
        test = [_test retain];
    }

    return test;
}

そして2つの便利な方法:

+ (NSString*)test {
    return [MyClass testHolderSet:NO newValue:nil];
}

+ (void)setTest:(NSString*)_test {
    [MyClass testHolderSet:YES newValue:_test];
}

それが役に立てば幸い!幸運を。

30

.mファイルで、変数を静的として宣言できます。

static ClassName *variableName = nil;

その後、+(void)initializeメソッドで初期化できます。

これは単純なC静的変数であり、JavaまたはC#がそれを考慮する意味では静的ではありませんが、同様の結果が得られることに注意してください。

29
pgb

.mファイルで、ファイルのグローバル変数を宣言します。

static int currentID = 1;

次に、initルーチンで、次のことを参照します。

- (id) init
{
    self = [super init];
    if (self != nil) {
        _myID = currentID++; // not thread safe
    }
    return self;
}

または、他のときに変更する必要がある場合(たとえば、openConnectionメソッドで)、そこで変更します。スレッドセーフではないことを忘れないでください。スレッドの問題が発生する可能性がある場合は、同期を行う必要があります(または、さらに良いのは、アトミックアドを使用することです)。

16
Peter N Lewis

Pgbが言ったように、「クラス変数」はなく、「インスタンス変数」のみがあります。クラス変数を行うObjective-Cの方法は、クラスの.mファイル内の静的なグローバル変数です。 「静的」は、変数がそのファイルの外部で使用できないことを保証します(つまり、外部にできません)。

11
Tom Dalling

ここにオプションがあります:

+(int)getId{
    static int id;
    //Do anything you need to update the ID here
    return id;
}

このメソッドはidにアクセスする唯一のメソッドであるため、このコードで何らかの方法で更新する必要があります。

3
Anonymous

(厳密に言えば質問への答えではありませんが、私の経験ではクラス変数を探すときに役立つと思われます)

クラスメソッドは、多くの場合、他の言語でクラス変数が果たす多くの役割を果たします(たとえば、テスト中に構成を変更します)。

@interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
@end
@implementation
+ (NSString*)theNameThing { return @"Something general"; }
- (void)doTheThing {
  [SomeResource changeSomething:[self.class theNameThing]];
}
@end

@interface MySpecialCase: MyCls
@end
@implementation
+ (NSString*)theNameThing { return @"Something specific"; }
@end

これで、クラスMyClsのオブジェクトは、Resource:changeSomething:の呼び出し時に文字列@"Something general"doTheThing:を呼び出しますが、MySpecialCaseから派生したオブジェクトは文字列@"Something specific"

2
Jacob Oscarson

クラスの名前をclassA.mmに変更し、C++機能を追加できます。

0
rd_

別の可能性は、小さなNSNumberサブクラスシングルトンを持つことです。

0