类方法中的@sychronized替代方法

时间:2014-07-29 17:32:24

标签: ios synchronization grand-central-dispatch

我希望有一个方法可以创建一个新对象,也可以根据标识符字符串返回一个现有对象。

这就是我所拥有的:

@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 个答案:

答案 0 :(得分: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;
    }
    
  3. 方法newRefrenceWithId:现在完全是线程安全的。

    修改:

    或者,您也可以使用并发 sync_queue并在块中读取和写入时使用dispatch_barrier_sync

    对象时使用dispatch_barrier_async

    如果您只需读取并返回共享对象的状态,则应使用dispatch_sync - 这允许并发读取。