Class级静态变量的原子性
Atomicity of Class-Level Static Variables
我正在使用一个 Objective-C class,它包含一个可以随时存储、检索或释放的静态变量:
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
我的问题是关于这个静态 class 级变量的原子性。 声明ivars 默认为strong, readwrite, nonatomic
,原子性由getter 和setter 定义。这也适用于静态变量吗?默认情况下 currentUser
是非原子的吗?要使 currentUser
原子化,我是否必须将 getter 和 setter 包装在 @synchronized(self) { ... }
块中?
所有变量都是非原子的。
当 属性 被声明为原子时,setter 和 getter 的合成代码包含额外的代码以使变量的访问成为原子。
对于普通的旧变量,没有任何代码的自动合成来使它们成为原子。如果你需要一个变量是原子的,你需要添加你自己的代码来使它的访问成为原子的。
使用 @synchronized
是一种选择。但是对于 static
变量,使用 @synchronized(self)
是行不通的,因为 class 的多个实例可以访问一个 static
变量,而 @synchronized(self)
只能确保没有两个来自同一实例的线程将访问静态,但它不会阻止另一个线程上的另一个实例也访问 static
变量。
static
的一个解决方案是使用 @synchronized([self class])
。
针对您问题中的情况的另一种解决方案是摆脱 static
变量并使用单例设置 class。然后单例可以跟踪当前用户。
我正在使用一个 Objective-C class,它包含一个可以随时存储、检索或释放的静态变量:
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
我的问题是关于这个静态 class 级变量的原子性。 strong, readwrite, nonatomic
,原子性由getter 和setter 定义。这也适用于静态变量吗?默认情况下 currentUser
是非原子的吗?要使 currentUser
原子化,我是否必须将 getter 和 setter 包装在 @synchronized(self) { ... }
块中?
所有变量都是非原子的。
当 属性 被声明为原子时,setter 和 getter 的合成代码包含额外的代码以使变量的访问成为原子。
对于普通的旧变量,没有任何代码的自动合成来使它们成为原子。如果你需要一个变量是原子的,你需要添加你自己的代码来使它的访问成为原子的。
使用 @synchronized
是一种选择。但是对于 static
变量,使用 @synchronized(self)
是行不通的,因为 class 的多个实例可以访问一个 static
变量,而 @synchronized(self)
只能确保没有两个来自同一实例的线程将访问静态,但它不会阻止另一个线程上的另一个实例也访问 static
变量。
static
的一个解决方案是使用 @synchronized([self class])
。
针对您问题中的情况的另一种解决方案是摆脱 static
变量并使用单例设置 class。然后单例可以跟踪当前用户。