【发布时间】:2009-03-30 04:09:04
【问题描述】:
也许这很明显,但我不知道如何在 Objective-C 中声明类属性。
我需要为每个类缓存一个字典,并想知道如何将它放入类中。
【问题讨论】:
标签: objective-c cocoa oop
也许这很明显,但我不知道如何在 Objective-C 中声明类属性。
我需要为每个类缓存一个字典,并想知道如何将它放入类中。
【问题讨论】:
标签: objective-c cocoa oop
属性在Objective-C中具有特定含义,但我认为您的意思是等同于静态变量的东西?例如。所有类型的 Foo 都只有一个实例?
要在 Objective-C 中声明类函数,请使用 + 前缀而不是 - 所以你的实现看起来像这样:
// Foo.h
@interface Foo {
}
+ (NSDictionary *)dictionary;
// Foo.m
+ (NSDictionary *)dictionary {
static NSDictionary *fooDict = nil;
if (fooDict == nil) {
// create dict
}
return fooDict;
}
【讨论】:
.-accessor 语法不依赖于 Objective-C 中的属性,它只是任何方法的编译快捷方式,它返回一些东西而不使用任何参数。在这种情况下,我更喜欢它——我个人更喜欢 . 语法用于客户端代码打算获取某些东西,而不是执行操作 的任何用法(即使实现代码可能会创建一次,或者执行副作用行动)。大量使用 . 语法也会导致代码更具可读性:[…]s 的存在意味着当提取使用 . 语法时正在完成一些重要的事情。
我正在使用这个解决方案:
@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end
@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end
我发现它作为单例模式的替代品非常有用。
要使用它,只需使用点符号访问您的数据:
Model.value = 1;
NSLog(@"%d = value", Model.value);
【讨论】:
self 在类方法中到底是什么意思?
self 是 the object that's received the message。由于classes are also objects,在这种情况下self 表示Model
@synchronized?
正如在 WWDC 2016/XCode 8 (what's new in LLVM session @5:05) 上看到的那样。类属性可以声明如下
@interface MyType : NSObject
@property (class) NSString *someString;
@end
NSLog(@"format string %@", MyType.someString);
请注意,类属性永远不会合成
@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
【讨论】:
static) 变量仍必须声明和使用,并且方法显式实现,就像以前一样。点语法以前也可以使用。总而言之,这听起来比实际更重要。
如果您正在寻找 @property 的类级别等价物,那么答案是“没有这样的东西”。但请记住,无论如何,@property 只是语法糖;它只是创建适当命名的对象方法。
您想创建访问静态变量的类方法,正如其他人所说,它们的语法略有不同。
【讨论】:
UIDevice.currentDevice.identifierForVendor 为我工作。
这是一种线程安全的方法:
// Foo.h
@interface Foo {
}
+(NSDictionary*) dictionary;
// Foo.m
+(NSDictionary*) dictionary
{
static NSDictionary* fooDict = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
// create dict
});
return fooDict;
}
这些编辑确保 fooDict 只创建一次。
来自Apple documentation:“dispatch_once - 在应用程序的生命周期内只执行一次块对象。”
【讨论】:
Initializer element is not a compile-time constant。
从 Xcode 8 开始,Objective-C 现在支持类属性:
@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end
由于永远不会合成类属性,因此您需要编写自己的实现。
@implementation MyClass
static NSUUID*_identifier = nil;
+ (NSUUID *)identifier {
if (_identifier == nil) {
_identifier = [[NSUUID alloc] init];
}
return _identifier;
}
@end
您可以使用类名上的普通点语法访问类属性:
MyClass.identifier;
【讨论】:
属性仅在对象中具有值,在类中没有。
如果你需要为一个类的所有对象存储一些东西,你必须使用一个全局变量。您可以通过在实现文件中声明 static 来隐藏它。
您还可以考虑使用对象之间的特定关系:您将主角色的角色分配给您类的特定对象,并将其他对象链接到该主对象。主人将把字典作为一个简单的财产。我想到了一棵树,就像 Cocoa 应用程序中用于视图层次结构的树。
另一种选择是创建一个专用类的对象,该类由您的“类”字典和与该字典相关的所有对象组成。这类似于 Cocoa 中的 NSAutoreleasePool。
【讨论】:
从 Xcode 8 开始,您可以使用 Berbie 回答的 class 属性。
但是,在实现中,您需要使用静态变量代替 iVar 为类属性定义类 getter 和 setter。
示例.h
@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end
示例.m
@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
if (_sharedSample==nil) {
[Sample setSharedSample:_sharedSample];
}
return _sharedSample;
}
+ (void)setSharedSample:(Sample *)sample {
_sharedSample = [[Sample alloc]init];
}
@end
【讨论】:
如果你有很多类级别的属性,那么单例模式可能是合适的。 像这样的:
// Foo.h
@interface Foo
+ (Foo *)singleton;
@property 1 ...
@property 2 ...
@property 3 ...
@end
和
// Foo.m
#import "Foo.h"
@implementation Foo
static Foo *_singleton = nil;
+ (Foo *)singleton {
if (_singleton == nil) _singleton = [[Foo alloc] init];
return _singleton;
}
@synthesize property1;
@synthesize property2;
@synthesise property3;
@end
现在访问您的类级属性,如下所示:
[Foo singleton].property1 = value;
value = [Foo singleton].property2;
【讨论】:
dispatch_once 会很容易。
[试试这个解决方案很简单] 你可以在 Swift 类中创建一个静态变量,然后从任何 Objective-C 类中调用它。
【讨论】: