Переменные уровня класса Objective-C - PullRequest
141 голосов
/ 30 июня 2009

У меня есть класс Film, в каждом из которых хранится уникальный идентификатор. В C #, Java и т. Д. Я могу определить статический int currentID и каждый раз, когда я устанавливаю ID, я могу увеличивать currentID, и изменение происходит на уровне класса, а не на уровне объекта. Можно ли это сделать в Objective-C? Мне было очень трудно найти ответ на этот вопрос.

Ответы [ 9 ]

157 голосов
/ 09 августа 2009

Описание проблемы :

  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 ++
30 голосов
/ 23 апреля 2011

Начиная с 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 Ответ: (не используйте это, это ужасно)

Если вы действительно не хотите объявлять глобальную переменную, есть другая опция, может быть, не совсем обычная :-), но работает ... Вы можете объявить метод "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;
}

И два удобных метода:

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

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

Надеюсь, это поможет! Удачи.

29 голосов
/ 30 июня 2009

В вашем файле .m вы можете объявить переменную как статическую:

static ClassName *variableName = nil;

Затем вы можете инициализировать его по вашему +(void)initialize методу.

Обратите внимание, что это обычная статическая переменная C и не является статической в ​​том смысле, в каком ее считают Java или C #, но даст аналогичные результаты.

16 голосов
/ 01 июля 2009

В вашем файле .m объявите глобальную переменную файла:

static int currentID = 1;

тогда в вашей процедуре инициализации, ссылайтесь на:

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

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

11 голосов
/ 01 июля 2009

Как сказал pgb, «переменных класса» нет, только «переменные экземпляра». Метод target-c для работы с переменными класса - это статическая глобальная переменная внутри файла .m класса. «Статический» гарантирует, что переменная не может быть использована вне этого файла (то есть она не может быть внешней).

3 голосов
/ 19 января 2012

Здесь будет вариант:

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

Обратите внимание, что этот метод будет единственным методом доступа к идентификатору, поэтому вам придется как-то обновить его в этом коде.

2 голосов
/ 22 октября 2012

(Строго говоря, не ответ на вопрос, но по моему опыту, вероятно, будет полезен при поиске переменных класса)

Метод класса часто может играть многие роли, которые переменная класса играет в других языках (например, измененная конфигурация во время тестов):

@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 голосов
/ 17 февраля 2013

Другой возможностью было бы иметь небольшой NSNumber подкласс синглтона.

0 голосов
/ 05 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...