我正在使用一个Objective-C类,它包含一个可以随时存储,检索或取消分配的静态变量:
User.h
@interface User : NSObject
/// Returns the current user if set, nil if not
+ (User * _Nullable)currentUser;
/// Sets the current user
+ (void)setCurrentUser:(NSString * _Nonnull)name;
/// Removes the current user
+ (void)removeCurrentUser;
// Getters
/// Returns the user's name if set, nil if there is no user set
@property (nullable, nonatomic, strong, readonly) NSString *name;
@end
User.m
@interface User ()
@property (nullable, nonatomic, strong, readwrite) NSString *name;
@end
@implementation User
#pragma mark - Static Variables
static User *currentUser;
#pragma mark - Static Object Setters and Getters
+ (User *)currentUser
{
return currentUser;
}
+ (void)setCurrentUser:(NSString * _Nonnull)name
{
currentUser = [[User alloc] initWithName:name];
}
+ (void)removeCurrentUser
{
currentUser = nil;
}
#pragma mark - init
- (instancetype)initWithName:(NSString * _Nonnull)name
{
self = [super init];
if (self) {
_name = name;
}
return self;
}
@end
我的问题是关于这个静态类级变量的原子性。 This question表示ivars默认为strong, readwrite, nonatomic
,并且原子性由getter和setter定义。这也适用于静态变量吗?默认情况下currentUser
是非原子的吗?为了使currentUser
原子,我必须在@synchronized(self) { ... }
块中包装我的getter和setter吗?
答案 0 :(得分:4)
所有变量都是非原子的。
当一个属性被声明为原子时,setter和getter的合成代码包含额外的代码,以使变量的访问成为原子。
使用普通的旧变量,没有任何代码的自动合成使它们成为原子。如果您需要一个原子变量,您需要添加自己的代码以使其访问原子。
使用@synchronized
是一种选择。但是对于static
变量,使用@synchronized(self)
将不起作用,因为类的多个实例可以访问static
变量而@synchronized(self)
只会确保没有来自同一个变量的两个线程实例将访问静态但不会阻止另一个线程上的另一个实例也访问static
变量。
static
的一个解决方案是使用@synchronized([self class])
。
问题的另一个解决方案是摆脱static
变量并使用单例设置类。然后单身人士可以跟踪当前用户。