答えが正しいとしても、エレガントで異なる解決策があります。
- (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;
}
スレッドの安全でないオブジェクトを使用する場合、コピーは重要です。これにより、変数の意図しない解放によるエラーを回避できます。スレッド セーフなエンティティは必要ありません。
より多くのキューが NSMutableDictionary を使用する場合は、プライベート キューを宣言し、setter を次のように変更します。
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);
}
});
}
重要!
それなしで独自のプライベートキューを設定する必要があります。
詳細な説明は、このすばらしいブログ記事にあります。