@sychronized альтернатива в методе класса
Я хочу иметь метод, который будет либо создавать новый объект, либо возвращать существующий на основе строки идентификатора.
Вот что у меня есть:
@implementation MyObject {
}
@synthesize data = _data;
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
// these methods are the only ones to be used for managing the MyObject life cycle
+ (NSMutableDictionary *)objectsDict
{
static NSMutableDictionary *map = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
map = [NSMutableDictionary new];
});
return map;
}
+ (MyObject *)getRefrenceForId:(NSString *)identifier
{
return [[MyObject objectsDict] objectForKey:identifier];
}
+ (MyObject *)newRefrenceWithId:(NSString *)identifier
{
MyObject *obj;
@synchronized (self) {
obj = [[MyObject objectsDict] objectForKey:identifier];
if (obj == nil) {
obj = [[MyObject alloc] init];
obj.identifier = identifier;
[[MyObject objectsDict] setObject:obj forKey:identifier];
NSLog(@"new instance of MyObject created with id:%@",identifier);
}
}
return obj;
}
+ (MyObject *)newRefrenceWithId:(NSString *)identifier andClassType:(Class)classType
{
MyObject *obj;
@synchronized (self) {
obj = [[MyObject objectsDict] objectForKey:identifier];
if (obj == nil) {
obj = [[MyObject alloc] initWithClassType:classType andId:identifier];
[[MyObject objectsDict] setObject:obj forKey:identifier];
NSLog(@"new instance of MyObject created with id:%@ of ClassType :%@",identifier,NSStringFromClass(classType));
}
}
return obj;
}
+ (void)deleteInstance:(NSString *)identifier
{
@synchronized (self) {
[[MyObject objectsDict] removeObjectForKey:identifier];
}
}
+ (void)clearAllMyObjectsFromMap
{
@synchronized (self) {
[[MyObject objectsDict] removeAllObjects];
}
}
Есть лучший способ сделать это? Я слышал, что @synchronized очень дорогостоящий процессор, но параллельные очереди GCD нельзя использовать в методах класса...
ОБНОВЛЕНИЕ: Где должна быть глобальная очередь синхронизации.. в init? Это метод экземпляра, поэтому я не работаю там...
1 ответ
Вы можете использовать GCD:
Создайте глобальную "очередь синхронизации", используя
dispatch_once
в свободной функции, определенной в области видимости модуля:static dispatch_queue_t get_sync_queue() { static dispatch_once_t onceToken; static dispatch_queue_t sync_queue; dispatch_once(&onceToken, ^{ sync_queue = dispatch_queue_create("my.sync_queue", DISPATCH_QUEUE_CONCURRENT); }); return sync_queue; }
Использовать эту очередь с
dispatch_sync
и блок, модифицирующий ваш объект:+ (MyObject *)newRefrenceWithId:(NSString *)identifier { __block MyObject *obj; dispatch_barrier_sync(get_sync_queue(), { obj = [[MyObject objectsDict] objectForKey:identifier]; if (obj == nil) { obj = [[MyObject alloc] init]; obj.identifier = identifier; [[MyObject objectsDict] setObject:obj forKey:identifier]; NSLog(@"new instance of MyObject created with id:%@",identifier); } }); return obj; }
метод newRefrenceWithId:
теперь полностью потокобезопасен.
Редактировать:
Кроме того, вы также можете использовать одновременный sync_queue и использовать dispatch_barrier_sync
при чтении и записи в блоке (как в вашем случае)
использование dispatch_barrier_async
при записи объекта (ов).
В случае, если вам просто нужно прочитать и вернуть состояние общего объекта, вы должны использовать dispatch_sync
- что позволяет одновременно читать.