Anche la risposta è corretta, non v'è una soluzione elegante e diverso:
- (id)init {
self = [super init];
if (self != nil) {
NSString *label = [NSString stringWithFormat:@"%@.isolation.%p", [self class], self];
self.isolationQueue = dispatch_queue_create([label UTF8String], NULL);
label = [NSString stringWithFormat:@"%@.work.%p", [self class], self];
self.workQueue = dispatch_queue_create([label UTF8String], NULL);
}
return self;
}
//Setter, write into NSMutableDictionary
- (void)setCount:(NSUInteger)count forKey:(NSString *)key {
key = [key copy];
dispatch_async(self.isolationQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
//Getter, read from NSMutableDictionary
- (NSUInteger)countForKey:(NSString *)key {
__block NSUInteger count;
dispatch_sync(self.isolationQueue, ^(){
NSNumber *n = self.counts[key];
count = [n unsignedIntegerValue];
});
return count;
}
La copia è importante quando si utilizza filo oggetti non sicuri, con questo si potrebbe evitare la possibile errore a causa di emissione accidentale della variabile . Non c'è bisogno di entità thread-safe.
Se più code vorrebbe utilizzare il NSMutableDictionary dichiarare una coda privata e cambiare il setter a:
self.isolationQueue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_CONCURRENT);
- (void)setCount:(NSUInteger)count forKey:(NSString *)key {
key = [key copy];
dispatch_barrier_async(self.isolationQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
IMPORTANTE!
è necessario impostare una propria coda privata senza di essa il dispatch_barrier_sync è solo un semplice dispatch_sync
spiegazione dettagliata è in questo marvelous blog article.
Non sono esperto di multithreading, ma so che il flag "atomic" (l'impostazione predefinita per @ sintetizza gli accessors) non garantisce la sicurezza del thread. Ho pensato la stessa cosa quando l'ho letto per la prima volta, comunque. –