Objective-C Statik Sınıf Düzeyi değişkenleri


143

Her biri benzersiz bir kimlik depolayan bir Sınıf Filmim var. C #, Java vb statik bir currentID tanımlayabilirsiniz ve her i kimliği ayarlamak i geçerli kimliği artırabilir ve değişiklik nesne düzeyinde değil sınıf düzeyinde oluşur. Bu, Objective-C ile yapılabilir mi? Bunun için bir cevap bulmakta zorlandım.

Yanıtlar:


158

Sorun Açıklaması :

  1. ClassA'nızın bir ClassB sınıfı değişkeni olmasını istiyorsunuz.
  2. Programlama dili olarak Objective-C kullanıyorsunuz.
  3. Objective-C, C ++ gibi sınıf değişkenlerini desteklemez.

Bir Alternatif :

Objective-C özelliklerini kullanarak sınıf değişkeni davranışını simüle etme

  1. ClassA.m içinde statik bir değişken tanımlayın / tanımlayın, böylece yalnızca classA yöntemleri (ve classA.m içine koyduğunuz her şey için) erişilebilir olacaktır.

  2. ClassB örneğiyle statik değişkeni yalnızca bir kez başlatmak için NSObject initialize class yönteminin üzerine yazın.

  3. Merak edeceksiniz, neden NSObject başlatma yönteminin üzerine yazmalıyım. Bu yöntemle ilgili Apple belgeleri şu cevaba sahiptir: "Çalışma zamanı, bir programdaki her sınıfa dersten tam olarak bir kez önce veya ondan miras alınan herhangi bir sınıfa program içinden ilk iletisini gönderir. (Bu nedenle yöntem sınıf kullanılmazsa asla çağrılamaz.) ".

  4. Herhangi bir ClassA sınıfı / örneği yönteminde statik değişkeni kullanmaktan çekinmeyin.

Kod örneği :

dosya: 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

Kaynaklar :

  1. Sınıf değişkenleri Objective-C ve C ++ yaklaşımlarını karşılaştırarak açıkladı

3
ClassA.m içinde statik bir Sınıf Sınıfı değişkeniniz olabilir mi?
keçi

6
bu aptalca bir soru olabilir ama peki ya hafızanın serbest bırakılması? uygulama çalıştığı sürece yaşamak zorunda olduğu için önemli değil mi?
samiq

1
@samiq, Amaç-C'ye bakın: Neden statik bir değişkeni tutmalıyım ? . Nesnenin işaretçisi silinemez, ancak nesnenin kendisi de silinebilir. Muhtemelen yayınlamak istemezsiniz çünkü büyük olasılıkla uygulama çalıştığı sürece etrafta olmasını istersiniz, ancak bırakırsanız bellekten tasarruf edersiniz, bu yüzden artık ihtiyacınız olmadığını biliyorsanız, o zaman bırak onu.
ma11hew28

5
İnitialize () işlevinin yalnızca bir kez çağrılması garanti edilirse, neden "if (! ClassVariableName)" koşuluna ihtiyacınız var?
jb

23
@jamie, initializeher sınıf için bir kez çağrılır (alt sınıflardan önce üst sınıflar), ancak bir alt sınıf geçersiz kılmazsa, initializeüst sınıf initializeyeniden çağrılır. Bu nedenle, bu kodun iki kez yürütülmesini istemiyorsanız bir koruma gereklidir. Bkz . Apple'ın Objective-C belgelerinde bir Sınıf Nesnesi Başlatma .
big_m

31

Xcode 8'den itibaren, Obj-C'de sınıf özelliklerini tanımlayabilirsiniz. Bu, Swift'in statik özellikleri ile birlikte çalışmak için eklendi.

Objective-C artık Swift tür özellikleri ile birlikte çalışan sınıf özelliklerini desteklemektedir. @Property (class) NSString * someStringProperty; olarak bildirilirler. Asla sentezlenmezler. (23891898)

İşte bir örnek

@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

Sonra bu şekilde erişebilirsiniz:

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

İşte bu eski cevabı düzenlemek için referans olarak kullandığım çok ilginç bir açıklayıcı gönderi .


2011 Cevap: (bunu kullanmayın, korkunç)

Gerçekten küresel bir değişken bildirmek istemiyorsanız, başka bir seçenek, belki de çok ortodoks değil :-), ama işe yarıyor ... İçinde statik bir değişken ile böyle bir "get & set" yöntemi bildirebilirsiniz:

+ (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;
}

Bu nedenle, değeri almanız gerekiyorsa, şunu arayın:

NSString *testVal = [MyClass testHolder:nil]

Ve sonra, ayarlamak istediğinizde:

[MyClass testHolder:testVal]

Bu pseudo-static-var değerini nil olarak ayarlamak istediğinizde, şu şekilde bildirebilirsiniz testHolder:

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

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

    return test;
}

Ve iki kullanışlı yöntem:

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

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

Umarım yardımcı olur! İyi şanslar.


Harika, ama gerçekten küresel bir değişken değil, çünkü diğer .mdosyalardan erişilemiyor ve bence Class.mdosya içinde "global" olması iyi bir şey .
ma11hew28

29

.M dosyanızda, bir değişkeni statik olarak bildirebilirsiniz:

static ClassName *variableName = nil;

Ardından +(void)initializeyönteminizde başlatabilirsiniz .

Bunun düz bir C statik değişkeni olduğunu ve Java veya C # anlamında statik olmadığını ve benzer sonuçlar vereceğini unutmayın.


16

.M dosyanızda bir dosya genel değişkeni bildirin:

static int currentID = 1;

o zaman başlangıç ​​rutininizde bunu yeniden ifade edin:

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

veya başka bir zamanda değiştirilmesi gerekiyorsa (örneğin, openConnection yönteminizde), o zaman orada artırın. İplik güvenli olmadığı gibi, herhangi bir iplik geçirme sorunu varsa senkronizasyon yapmanız (veya daha iyisi, atomik bir ekleme kullanmanız) gerektiğini unutmayın.


11

Pgb'nin dediği gibi, "sınıf değişkenleri" yoktur, sadece "örnek değişkenleri" vardır. Sınıf değişkenleri yapmanın objektif-c yöntemi, sınıfın .m dosyası içindeki statik bir global değişkendir. "Statik", değişkenin bu dosyanın dışında kullanılamamasını sağlar (örn. Harici olamaz).


3

İşte bir seçenek:

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

Bu yöntemin kimliğe erişmek için tek yöntem olacağını unutmayın, bu nedenle bu kodda bir şekilde güncellemeniz gerekecektir.


2

(Kesin olarak, sorunun cevabı değil, deneyimlerime göre sınıf değişkenleri ararken faydalı olması muhtemeldir)

Bir sınıf yöntemi genellikle bir sınıf değişkeninin diğer dillerdeki rollerinin çoğunu oynatabilir (örneğin, testler sırasında değişen yapılandırma):

@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

Şimdi, bir sınıf nesnesi MyClsçağrıldığında Resource:changeSomething:dize ile @"Something general"çağrılır doTheThing:, ancak MySpecialCasedize ile türetilmiş bir nesne @"Something specific".


0

u sınıfı classA.mm olarak yeniden adlandırabilir ve C ++ özelliklerini ekleyebilir.


0

Başka bir olasılık, küçük bir NSNumberalt sınıf singletonuna sahip olmak olacaktır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.