Змінні рівня статичного класу Objective-C


143

У мене є клас фільму, у кожному з яких зберігається унікальний ідентифікатор. У C #, Java тощо я можу визначити статичний int currentID і кожен раз, коли я встановлюю ідентифікатор, я можу збільшувати currentID, і зміна відбувається на рівні класу, а не на об'єктному рівні. Чи можна це зробити в Objective-C? Мені дуже важко було знайти відповідь на це.

Відповіді:


158

Опис випуску :

  1. Ви хочете, щоб ваш ClassA мав змінну класу ClassB.
  2. Ви використовуєте Objective-C як мову програмування.
  3. Objective-C не підтримує змінні класу, як це робить C ++.

Одна альтернатива :

Моделюйте змінну поведінки класу за допомогою функцій Objective-C

  1. Заявіть / визначте статичну змінну у classA.m, щоб вона була доступною лише для методів classA (і всього, що ви помістите всередину classA.m).

  2. Перезапишіть метод класу ініціалізації NSObject, щоб ініціалізувати лише один раз статичну змінну з екземпляром ClassB.

  3. Вам буде цікаво, чому я повинен перезаписати метод ініціалізації NSObject. Документація 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 ++

3
Чи можете ви мати статичну змінну типу ClassA в classA.m?
козячі посилання

6
це може бути дурним питанням, але як щодо звільнення згаданої пам'яті? не має значення, оскільки він повинен жити, поки працює програма?
samq

1
@samiq, перевірити Objective-C: Чому зберігати статичну змінну? . Вказівник на об’єкт не можна видалити, але сам об'єкт може. Ви, мабуть, не хочете його випускати, тому що ви, швидше за все, хочете його навколо, поки програма працює, але ви збережете пам'ять, якщо ви випустите її, тож якщо ви знаєте, що вона вам більше не потрібна, то вам слід відпустіть його.
ma11hew28

5
Якщо ініціалізація () гарантовано викликається лише один раз, навіщо вам потрібно умовне "if (! ClassVariableName)"?
jb

23
@jamie, initializeвикликається один раз для кожного класу (надкласи перед підкласами), але якщо підклас не перекриває initialize, батьківський клас initializeбуде викликаний знову. Отже, охорона потрібна, якщо ви не хочете, щоб цей код виконувався двічі. Див. Ініціалізація об’єкта класу в документах Apple Objective-C.
big_m

31

Станом на Xcode 8, ви можете визначити властивості класу в Obj-C. Це було додано до взаємодії зі статичними властивостями Свіфта.

Тепер 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]

У випадку, коли ви хочете встановити цю псевдостатичну вару на нуль, ви можете оголосити testHolderтак:

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

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

    return test;
}

І два зручні методи:

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

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

Сподіваюся, це допомагає! Удачі.


Класно, але це насправді не є глобальною змінною, оскільки до неї не можна отримати доступ з інших .mфайлів, і я думаю, що це добре, щоб вона була "глобальною" у Class.mфайлі.
ma11hew28

29

У файлі .m ви можете оголосити змінну статичною:

static ClassName *variableName = nil;

Потім ви можете ініціалізувати його на своєму +(void)initializeметоді.

Зверніть увагу, що це звичайна статична змінна C і не є статичною в сенсі Java або C # вважайте це, але дасть подібні результати.


16

У своєму .m файлі оголосіть глобальну змінну файлу:

static int currentID = 1;

то в своїй ініціальній процедурі зверніть увагу на це:

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

або якщо це потрібно змінити в інший час (наприклад, у вашому методі openConnection), збільшуйте його там. Пам’ятайте, що це не безпечно для потоків, як це є, вам потрібно зробити синхронізацію (а ще краще, використовувати атомну добавку), якщо можуть виникнути проблеми з ниткою.


11

Як сказав pgb, немає "змінних класу", "лише" змінних примірника. " Спосіб виконання змінних класів Obje-c - це статична глобальна змінна всередині .m-файла класу. "Статичний" гарантує, що змінна не може бути використана поза цим файлом (тобто вона не може бути зовнішньою).


3

Тут буде варіант:

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

Зауважте, що цей метод буде єдиним методом доступу до ідентифікатора, тому вам доведеться якось оновити його в цьому коді.


2

(Власне кажучи, це не відповідь на питання, але, на мій досвід, мабуть, це буде корисно при пошуку змінних класу)

Метод класу часто може грати багато ролей, які змінна класу виконувала б іншими мовами (наприклад, змінена конфігурація під час тестів):

@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".


0

Ви можете перейменувати клас у classA.mm і додати в нього функції C ++.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.