web-dev-qa-db-ja.com

Objective-Cでクラスレベルのプロパティを宣言するにはどうすればよいですか?

たぶんこれは明らかですが、Objective-Cでクラスプロパティを宣言する方法がわかりません。

クラスごとにディクショナリをキャッシュする必要があり、それをクラスにどのように入れるか疑問に思います。

197
mamcx

objective-Cではプロパティに特定の意味がありますが、静的変数に相当するものを意味すると思いますか?例えば。すべてのタイプのFooに対して1つのインスタンスのみですか?

Objective-Cでクラス関数を宣言するには、-の代わりに+プレフィックスを使用するため、実装は次のようになります。

// Foo.h
@interface Foo {
}

+ (NSDictionary *)dictionary;

// Foo.m
+ (NSDictionary *)dictionary {
  static NSDictionary *fooDict = nil;
  if (fooDict == nil) {
    // create dict
  }
  return fooDict;
}
186
Andrew Grant

私はこのソリューションを使用しています:

@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end

@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end

そして、Singletonパターンの代替として非常に有用であることがわかりました。

使用するには、ドット表記でデータにアクセスするだけです:

Model.value = 1;
NSLog(@"%d = value", Model.value);
109
spooki

WWDC 2016/XCode 8で見られるように( LLVMセッションの新機能 @ 5:05)。クラスプロパティは次のように宣言できます

@interface MyType : NSObject
@property (class) NSString *someString;
@end

NSLog(@"format string %@", MyType.someString);

クラスプロパティは決して合成されないことに注意してください

@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
77
Alex Nolasco

@propertyと同等のクラスレベルを探している場合、答えは「そのようなものはありません」です。ただし、@propertyは、とにかく構文上の砂糖にすぎないことを忘れないでください。適切な名前のオブジェクトメソッドを作成するだけです。

他の人が言ったように、わずかに異なる構文を持つ静的変数にアクセスするクラスメソッドを作成します。

63
Jim Puls

スレッドセーフな方法は次のとおりです。

// Foo.h
@interface Foo {
}

+(NSDictionary*) dictionary;

// Foo.m
+(NSDictionary*) dictionary
{
  static NSDictionary* fooDict = nil;

  static dispatch_once_t oncePredicate;

  dispatch_once(&oncePredicate, ^{
        // create dict
    });

  return fooDict;
}

これらの編集により、fooDictが一度だけ作成されることが保証されます。

From Apple documentation : "dispatch_once-アプリケーションの有効期間中、ブロックオブジェクトを一度だけ実行します。"

21
Quentin

Xcode 8現在、Objective-Cはクラスプロパティをサポートしています。

@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end

クラスプロパティは決して合成されないため、独自の実装を記述する必要があります。

@implementation MyClass
static NSUUID*_identifier = nil;

+ (NSUUID *)identifier {
  if (_identifier == nil) {
    _identifier = [[NSUUID alloc] init];
  }
  return _identifier;
}
@end

クラス名に通常のドット構文を使用して、クラスプロパティにアクセスします。

MyClass.identifier;
11
berbie

プロパティは、クラスではなくオブジェクトにのみ値を持ちます。

クラスのすべてのオブジェクトに対して何かを保存する必要がある場合は、グローバル変数を使用する必要があります。実装ファイルでstaticを宣言することで非表示にできます。

オブジェクト間の特定の関係の使用を検討することもできます。マスターの役割をクラスの特定のオブジェクトに関連付け、他のオブジェクトをこのマスターにリンクします。マスターは辞書を単純なプロパティとして保持します。 Cocoaアプリケーションのビュー階層に使用されるツリーのようなものだと思います。

別のオプションは、「クラス」辞書とこの辞書に関連するすべてのオブジェクトのセットの両方で構成される専用クラスのオブジェクトを作成することです。これは、CocoaのNSAutoreleasePoolのようなものです。

7
mouviciel

Xcode 8以降では、Berbieが回答したclassプロパティ属性を使用できます。

ただし、実装では、iVarの代わりに静的変数を使用して、クラスプロパティのクラスゲッターとセッターの両方を定義する必要があります。

Sample.h

@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end

Sample.m

@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
   if (_sharedSample==nil) {
      [Sample setSharedSample:_sharedSample];
   }
   return _sharedSample;
}

+ (void)setSharedSample:(Sample *)sample {
   _sharedSample = [[Sample alloc]init];
}
@end
5
Jean-Marie D.

クラスレベルのプロパティが多数ある場合、シングルトンパターンが適切である可能性があります。このようなもの:

// Foo.h
@interface Foo

+ (Foo *)singleton;

@property 1 ...
@property 2 ...
@property 3 ...

@end

そして

// Foo.m

#import "Foo.h"

@implementation Foo

static Foo *_singleton = nil;

+ (Foo *)singleton {
    if (_singleton == nil) _singleton = [[Foo alloc] init];

    return _singleton;
}

@synthesize property1;
@synthesize property2;
@synthesise property3;

@end

次のように、クラスレベルのプロパティにアクセスします。

[Foo singleton].property1 = value;
value = [Foo singleton].property2;
2
Pedro Borges