【发布时间】:2010-11-06 23:41:16
【问题描述】:
我有一个类 Film,每个类都存储一个唯一的 ID。在 C#、Java 等中,我可以定义一个静态 int currentID,每次设置 ID 时,我都可以增加 currentID,并且更改发生在类级别而不是对象级别。这可以在Objective-C中完成吗?我发现很难找到答案。
【问题讨论】:
标签: objective-c variables static
我有一个类 Film,每个类都存储一个唯一的 ID。在 C#、Java 等中,我可以定义一个静态 int currentID,每次设置 ID 时,我都可以增加 currentID,并且更改发生在类级别而不是对象级别。这可以在Objective-C中完成吗?我发现很难找到答案。
【问题讨论】:
标签: objective-c variables static
问题描述:
另一种选择:
使用 Objective-C 特性模拟类变量行为
在 classA.m 中声明/定义一个静态变量,以便它只能被 classA 方法(以及您放入 classA.m 中的所有内容)访问。
重写 NSObject 的初始化类方法,只用 ClassB 的实例初始化静态变量一次。
你会想,我为什么要覆盖 NSObject 的初始化方法。关于此方法的 Apple 文档给出了答案:“运行时恰好在程序中的每个类或从它继承的任何类从程序中发送其第一条消息之前一次向程序中的每个类发送初始化。(因此,该方法如果不使用该类,则可能永远不会被调用。)”。
在任何 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
参考文献:
【讨论】:
initialize 为每个类调用一次(超类在子类之前),但如果子类没有覆盖initialize,父类initialize 将被再次调用。因此,如果您不希望该代码执行两次,则需要一个守卫。请参阅 Apple 的 Objective-C 文档中的 Initializing a Class Object。
从 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;
这是一个非常有趣的explanatory post,我用作参考来编辑这个旧答案。
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 文件中是“全局”的就可以了。跨度>
在您的 .m 文件中,您可以将变量声明为静态:
static ClassName *variableName = nil;
然后你可以在你的 +(void)initialize 方法上初始化它。
请注意,这是一个普通的 C 静态变量,并不是 Java 或 C# 所认为的静态变量,但会产生类似的结果。
【讨论】:
在您的 .m 文件中,声明一个文件全局变量:
static int currentID = 1;
然后在您的 init 例程中,参考:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
或者如果它需要在其他时间更改(例如在您的 openConnection 方法中),则在此处增加它。请记住,它不是线程安全的,如果可能存在任何线程问题,您需要进行同步(或者更好的是,使用原子添加)。
【讨论】:
正如 pgb 所说,没有“类变量”,只有“实例变量”。做类变量的objective-c方式是类的.m文件内的静态全局变量。 “静态”确保变量不能在该文件之外使用(即它不能是外部的)。
【讨论】:
这是一个选项:
+(int)getId{
static int id;
//Do anything you need to update the ID here
return id;
}
请注意,此方法将是访问 id 的唯一方法,因此您必须在此代码中以某种方式对其进行更新。
【讨论】:
(严格来说不是问题的答案,但根据我的经验,在查找类变量时可能很有用)
类方法通常可以扮演类变量在其他语言中的许多角色(例如,在测试期间更改配置):
@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 类的对象在调用@"Something general" 时使用字符串@"Something general" 调用Resource:changeSomething:,但是从MySpecialCase 派生的对象使用字符串@"Something specific"。
【讨论】:
您可以将类重命名为 classA.mm 并在其中添加 C++ 功能。
【讨论】:
另一种可能性是有一个小NSNumber 子类单例。
【讨论】: