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。然后单例可以跟踪当前用户。