Вопрос по static, objective-c, variables – Objective C Статические переменные уровня класса

141

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

Ваш Ответ

9   ответов
16

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

static int currentID = 1;

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

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

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

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

3

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

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

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

30

Начиная с Xcode 8, вы можете определить свойства класса в Obj-C. Это было добавлено для взаимодействия со статическими свойствами Swift.

Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as: @property (class) NSString *someStringProperty;. They are never synthesized. (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 Answer: (не используйте это, это ужасно)

Если вы действительно не хотите объявлять глобальную переменную, есть другая опция, может быть, не совсем обычная :-), но она работает ... Вы можете объявить & quot; get & amp; set & quot; метод, подобный этому, со статической переменной внутри:

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

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

Круто, но это на самом деле не глобальная переменная, потому что к ней нельзя получить доступ из других.m файлы, и я думаю, что это нормально, чтобы он был "глобальным" в пределахClass.m файл.
0

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

29

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

static ClassName *variableName = nil;

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

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

пожалуйста исправьте:+(void)initialize это метод
156

Issue Description:

  1. You want your ClassA to have a ClassB class variable.
  2. You are using Objective-C as programming language.
  3. Objective-C does not support class variables as C++ does.

One Alternative:

Имитация поведения переменной класса с использованием возможностей Objective C

  1. Declare/Define an static variable within the classA.m so it will be only accessible for the classA methods (and everything you put inside classA.m).

  2. Overwrite the NSObject initialize class method to initialize just once the static variable with an instance of ClassB.

  3. You will be wondering, why should I overwrite the NSObject initialize method. Apple documentation about this method has the answer: "The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.)".

  4. Feel free to use the static variable within any ClassA class/instance method.

Code sample:

файл: 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

References:

  1. Class variables explained comparing Objective-C and C++ approaches
Можете ли вы иметь статическую переменную типа ClassA внутри classA.m?
это может быть глупый вопрос, но как насчет освобождения памяти? не имеет значения, потому что он должен жить так долго, пока приложение работает?
Если initialize () гарантированно вызывается только один раз, зачем вам нужно условное выражение «if (! ClassVariableName)»?
@samiq, зацениObjective-C: Why retain a static variable?, Указатель на объект не может быть удален, но сам объект может быть удален. Вы, вероятно, не хотите выпускать его, потому что вы, скорее всего, захотите его использовать до тех пор, пока приложение работает, но вы сэкономите память, если вы его отпустите, поэтому, если вы знаете, что он вам больше не нужен, тогда вам следует отпустите это.
@jamie,initialize вызывается один раз для каждого класса (суперклассы перед подклассами), но если подкласс не переопределяетinitializeродительский классinitialize позвонят снова. Следовательно, требуется защита, если вы не хотите, чтобы этот код выполнялся дважды. УвидетьInitializing a Class Object в документах Apple Objective-C.
11

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

0

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

Похожие вопросы