Objective-C静态类级别变量


143

我有一个Film类,每个类都存储一个唯一的ID。在C#,Java等中,我可以定义一个静态int currentID,每次设置ID时,我可以增加currentID,并且更改发生在类级别而不是对象级别。可以在Objective-C中完成吗?我发现很难找到答案。

Answers:


158

问题说明

  1. 您希望您的ClassA具有一个ClassB类变量。
  2. 您正在使用Objective-C作为编程语言。
  3. 与C ++一样,Objective-C不支持类变量。

一种选择

使用Objective-C功能模拟类变量行为

  1. 在classA.m中声明/定义一个静态变量,以便只能对classA方法(以及放在classA.m中的所有内容)进行访问。

  2. 覆盖NSObject初始化类方法,以使用ClassB实例仅对静态变量进行一次初始化。

  3. 您会想知道,为什么我应该覆盖NSObject的initialize方法。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.m中使用TypeA类型的静态变量吗?
山羊链接2010年

6
这可能是一个愚蠢的问题,但是释放所说的记忆呢?没关系,因为它必须能在应用程序运行的前提下生存?
samiq 2011年

1
@samiq,请查看Objective-C:为什么要保留静态变量?。指向对象的指针不能删除,但是对象本身可以删除。您可能不想发布它,因为您很可能希望在应用程序运行期间一直使用它,但是如果发布它,您将节省内存,因此,如果您知道不再需要它,则应该释放它。
ma11hew28 2011年

5
如果保证initialize()仅被调用一次,那么为什么需要条件“ if(!classVariableName)”?
jb

23
@jamie,initialize每个类(超类先于子类)被调用一次,但是如果子类没有重写initialize,则父类initialize将被再次调用。因此,如果您不希望该代码执行两次,则需要一个保护措施。请参阅Apple的Objective-C文档中的初始化类对象
big_m 2011年

31

从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]

如果您希望能够将此伪静态变量设置为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文件内将其“全局”是可以的。
ma11hew28 2011年

29

在您的.m文件中,您可以将变量声明为静态变量:

static ClassName *variableName = nil;

然后可以在您的+(void)initialize方法上对其进行初始化。

请注意,这是一个普通的C静态变量,就Java或C#而言,它不是静态的,但是会产生相似的结果。


16

在您的.m文件中,声明文件全局变量:

static int currentID = 1;

然后在您的init例程中引用:

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

或者如果需要在其他时间更改(例如,在openConnection方法中),则在该位置增加它。请记住,它不是当前的线程安全的,如果可能存在任何线程问题,则需要进行同步(或者更好的是使用原子添加)。


11

正如pgb所说,没有“类变量”,只有“实例变量”。类变量的Objective-C方法是类.m文件中的静态全局变量。“静态”可确保该变量不能在该文件外部使用(即不能被外部使用)。


3

这是一个选择:

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

请注意,此方法将是访问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

现在,class对象在MyCls调用时Resource:changeSomething:使用字符串@"Something general"进行调用doTheThing:,而对象从MySpecialCasestring 派生@"Something specific"


0

您可以将类重命名为classA.mm并在其中添加C ++功能。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.