@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:

  1. Создайте глобальную "очередь синхронизации", используя 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;
     }
    
  2. Использовать эту очередь с 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 - что позволяет одновременно читать.

Другие вопросы по тегам