Переменные уровня класса Objective-C

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

Ответ 1

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

  • Вы хотите, чтобы ваш ClassA имел переменную класса ClassB.
  • Вы используете Objective-C в качестве языка программирования.
  • Objective-C не поддерживает переменные класса, как это делает С++.

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

Имитировать поведение переменной класса с помощью Objective-C функций

  • Объявить/определить статическую переменную в классеA.m, поэтому она будет доступна только для методов classA (и всего, что вы помещаете внутри классаA.m).

  • Перезаписать метод инициализации класса NSObject для инициализации только после статической переменной с экземпляром ClassB.

  • Вам будет интересно, почему я должен перезаписать метод инициализации NSObject. Документация Apple об этом методе имеет ответ: "Время выполнения отправляет инициализацию каждому классу в программе ровно один раз перед классом или любым наследуемым от него классом, отправляется его первое сообщение из программы (таким образом, метод никогда не будет вызываться, если класс не используется.)".

  • Не стесняйтесь использовать статическую переменную в любом классе класса/экземпляре класса.

Пример кода:

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

Ссылки

Ответ 2

Как и в 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]

В случае, если вы хотите установить этот псевдостатический-var на 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];
}

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

Ответ 3

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

static ClassName *variableName = nil;

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

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

Ответ 4

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

static int currentID = 1;

то в вашей процедуре инициализации обратитесь к следующему:

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

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

Ответ 5

Как сказано в pgb, нет "переменных класса", только "переменных экземпляра". objective-c способ выполнения переменных класса - статическая глобальная переменная внутри .m файла класса. "Статический" гарантирует, что переменная не может использоваться вне этого файла (т.е. Она не может быть extern).

Ответ 6

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

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

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

Ответ 7

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

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

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

Ответ 8

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

Ответ 9

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