Связанный объект времени выполнения Objective C с NSMutable словарем

Ссылка из этой публикации. Я реализовал похожую категорию, используя ту же концепцию использования NSMutableDictionary для хранения необходимой мне информации. Но есть одна вещь, которая смущает меня в оригинальном посте

- (NSMutableDictionary *)addl_associatedDictionary
{
     NSMutableDictionary *res = nil;
     @synchronized(self) 
     {
        if (!(res = [self addl_associatedDictionaryPrimitive])) 
        {
           res = [self addl_generateAssociatedDictionary];
        }
     }
    return res;
}

Я знаю, что ключевое слово @synchronized является защитой для mutilthread. но когда я перебираю другие примеры, большинство из них не используют защиту. так нужна ли защита? также я могу использовать статический dispatch_once_t для замены @synchronized? ниже мои фрагменты кода в.m файле

@dynamic associatedDict;

-(void)setAssociateValue:(NSMutableDictionary*)dict
{
    objc_setAssociatedObject(self, @selector(associatedDict), dict,   OBJC_ASSOCIATION_RETAIN);
} 

-(id)getAssociateValue
{
    return objc_getAssociatedObject(self, @selector(associatedDict));
}

-(NSMutableDictionary*)associatedDict
{
    NSMutableDictionary* dict=[self getAssociateValue];
    if(!dict)
    {
       dict=[[NSMutableDictionary alloc]init];
       [self setAssociatedDict:dict];
    }
    return dict;
 } 


 -(void)setAssociateDict:(NSMutableDictionary *)associatedDict
{
    [self setAssociatedDict:associatedDict];
}

-(id)associate_getObjectForKey:(NSString*)key
{
    return self.associatedDict[key];
}

-(void)associate_setObject:(id)obj forKey:(NSString*)key
{
   [self.associatedDict setObject:obj forKey:key];
}

2 ответа

Решение

Например, это может помочь ответить на подразумеваемую озабоченность по поводу затрат на блокировку: я заметил, что вы используете OBJC_ASSOCIATION_RETAIN скорее, чем OBJC_ASSOCIATION_RETAIN_NONATOMIC, Это может показаться излишним, учитывая ваши @synchronize в том, что если у вас есть последнее, то вы можете отказаться от блокировки на первом. В ту минуту вы платите дважды за синхронизацию. Либо плати один раз, либо не плати вообще.

Лучшее общее решение может быть:

NSMutableDictionary *res; // no need to assign to `nil`; it's implied in ARC

// you're using an atomic property, so this is inherently safe
if (!(res = [self addl_associatedDictionaryPrimitive])) 
{
    // okay, doesn't exist, but two or more threads may get to
    // here simultaneously so we'll need to synchronise, and...
    @synchronized(self) 
    {
        // ... check again. As someone else may already have proceeded past the
        // outer if and created it while this thread was waiting to
        // enter the synchronised block. Assuming this dictionary
        // is created more rarely than it's accessed, this is no great issue
        if (!(res = [self addl_associatedDictionaryPrimitive])) 
        {
           res = [self addl_generateAssociatedDictionary];
        }
    }
}
return res;

... и придерживаться OBJC_ASSOCIATION_RETAIN, Также обратите внимание на точку зрения CRD: изменяемые словари сами по себе не являются потокобезопасными. Так что если вам действительно нужна безопасность потоков, то это не совсем решит проблему. Если вам не нужна безопасность потоков, переключитесь на OBJC_ASSOCIATION_RETAIN_NONATOMIC и выбросить @synchronized,

Возвращаясь назад, нет, вы не можете просто использовать dispatch_once_t для этой конкретной задачи. Правильное использование dispatch_once_t требуется глобальная переменная, и ваша задача должна быть выполнена один раз для каждого экземпляра объекта - т.е. вам потребуется уникальная глобальная переменная для каждого экземпляра...

Вам нужна защита @synchronized? Это сделано для того, чтобы два или более потоков не создавали словарь. Без этого при первом вызове из каждого потока, в зависимости от времени, конечно, каждый может вернуть свой словарь. При последующих вызовах каждый из них будет возвращать словарь, созданный последним потоком для назначения соответствующей переменной, все остальные созданные словари будут потеряны.

Важно: NSMutableDictionary сам по себе не является потокобезопасным. Если у вас есть несколько потоков, читающих и пишущих словарь, то вам нужна дополнительная синхронизация / блокировка, чтобы избежать проблем. Есть несколько способов сделать это, просто найдите и найдите решение, которое соответствует вашим потребностям. Конечно, если вы не имеете несколько потоков все это спорно, NSMutableDictionary может и используется безопасно все время, не будучи потокобезопасным.

НТН

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