回答:
問題の説明:
1つの代替:
Objective-Cの機能を使用してクラス変数の動作をシミュレートする
classA.m内で静的変数を宣言/定義して、classAメソッド(およびclassA.m内に配置したすべてのもの)のみがアクセスできるようにします。
NSObject initialize classメソッドを上書きして、静的変数をClassBのインスタンスで一度だけ初期化します。
NSObjectのinitializeメソッドをなぜ上書きする必要があるのか疑問に思われるでしょう。このメソッドに関するAppleのドキュメントの答えは次のとおりです。「ランタイムは、クラスまたはそのクラスから継承するクラスがプログラム内から最初のメッセージを送信する直前に、プログラム内の各クラスに初期化を1回送信します(したがって、メソッドクラスが使用されていない場合、呼び出されることはありません。) "
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
参照:
initialize
は各クラス(サブクラスの前のスーパークラス)ごとに1回呼び出されますがinitialize
、サブクラスがをオーバーライドしない場合、親クラスinitialize
が再度呼び出されます。したがって、そのコードを2回実行したくない場合は、ガードが必要です。AppleのObjective-Cドキュメントの「クラスオブジェクトの初期化」を参照してください。
Xcode 8以降、Obj-Cでクラスプロパティを定義できます。これは、Swiftの静的プロパティと相互運用するために追加されました。
Objective-Cは、Swiftタイプのプロパティと相互運用するクラスプロパティをサポートするようになりました。@property(クラス)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回答:(これは使わないでください、ひどいです)
本当にグローバル変数を宣言したくない場合は、別のオプションがあり、おそらくあまりオーソドックスではないかもしれませんが:-)機能します...静的変数を使用して、次のような「get&set」メソッドを宣言できます。
+ (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]
この疑似静的変数を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];
}
それが役に立てば幸い!幸運を。
.m
ファイルからアクセスできないため、実際にはグローバル変数ではありませんClass.m
。ファイル内で「グローバル」にしても問題ないと思います。
.mファイルで、ファイルグローバル変数を宣言します。
static int currentID = 1;
それからあなたのinitルーチンで、それを参照してください:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
または、別のときに変更する必要がある場合(たとえば、openConnectionメソッド内)、そこでインクリメントします。現状ではスレッドセーフではないことに注意してください。スレッド化の問題が発生する可能性がある場合は、同期化を行う必要があります(さらに、アトミックな追加を使用する必要があります)。
(厳密に言えば質問への回答ではありませんが、私の経験では、クラス変数を探すときに役立つ可能性があります)
多くの場合、クラスメソッドは、クラス変数が他の言語で果たす多くの役割を果たします(たとえば、テスト中に構成が変更されます)。
@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"
。
別の可能性は、小さなNSNumber
サブクラスのシングルトンを持つことです。