2016-05-06 2 views
-1

Я работаю с классом 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 по умолчанию, а атомарность определяется получателем и сеттером. Это относится также и к статическим переменным? Есть currentUser неатомный по умолчанию? Чтобы сделать атомарным, мне пришлось бы обернуть мой геттер и сеттер в @synchronized(self) { ... } блоках?

ответ

4

Все переменные неатомные.

Когда свойство объявлено атомарным, синтезированный код для сеттера и геттера включает дополнительный код, чтобы сделать доступ переменной доступной.

С простыми старыми переменными нет никакого автоматического синтеза любого кода, чтобы сделать их атомарными. Если вам нужна переменная, чтобы быть атомарной, вам нужно добавить свой собственный код, чтобы сделать его доступ атомом.

Использование @synchronized является одним из вариантов. Но для переменной static использование @synchronized(self) не будет работать, потому что несколько экземпляров класса могут обращаться к переменной static, а @synchronized(self) будет гарантировать, что ни один из двух потоков из того же экземпляра не получит доступ к статике, но не будет препятствовать другому экземпляру в другом потоке от доступа к переменной static.

Одним из решений для static будет использование @synchronized([self class]).

Другое решение для вашего вопроса в том, чтобы избавиться от переменной static и настроить класс с помощью Singleton. Затем синглтон мог отслеживать текущего пользователя.

+0

Будет ли '@synchronized (self)' работать из метода класса, а не с помощью метода экземпляра (поскольку «self» в основном относится к «классу», а не к экземпляру)? – NSGod

+0

@NSGod Это будет работать в методе класса и в сочетании с использованием '@synchronized ([self class])' в методах экземпляра, весь доступ будет синхронизирован с любым методом класса/экземпляра. Существует один случай, когда это происходит, и если есть какие-либо функции C в файле .m, которые также получают доступ к переменной 'static'. – rmaddy

+0

Он также терпит неудачу, если есть подклассы. Если '+ currentUser' вызывается как для этого класса, так и для его подкласса, тогда' self' будет представлять собой две разные вещи, и обращения не будут синхронизированы. Safest будет '@synchronized ([Пользовательский класс])' или явным блокировкой. –

Смежные вопросы