@ryancrunchi是正確的:
你」在每次閱讀中重寫self.releasesDict。因此,在您編寫 塊時,self.releasesDict的值將是系統執行的最後一次讀取。
...但他提出的解決方案不能保護字典免受併發寫入,並且NSMutableDictionary
本質上不是線程安全的。您必須保護它免受併發讀取+寫入和/或寫入+寫入。這裏是你可以做的一個方法(一切的詳細解說的評論正在做):
// A local (non-shared) mutable dictionary. Using a local dictionary allows us to know that no one
// else is reading from or writing to it concurrently, which is not guaranteed if we use self.releasesDict
NSMutableDictionary* localDict = [NSMutableDictionary dictionary];
// Your original concurrent queue
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.myapp.myqueue", DISPATCH_QUEUE_CONCURRENT);
// A serial queue to protect localDict from reading and writing.
dispatch_queue_t localDictWriteQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
// Make this queue target the concurrent queue. Not strictly required, but you had everything executing on
// concurrentQueue before, and this preserves that, while also protecting localDict.
dispatch_set_target_queue(localDictWriteQueue, concurrentQueue);
// A dispatch group that allows us to perform an operation only after all the constituent writes have finished.
dispatch_group_t group = dispatch_group_create();
// For each platform, enter the group, then fire off the concurrent block
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
// Fetch into a dictionary that is local to the block.
NSDictionary* x = [self getDataWithPlatform:@"ps4"];
// Then, on the serial localDictWriteQueue merge those entries into the shared local dictionary
dispatch_async(localDictWriteQueue, ^{
[localDict addEntriesFromDictionary: x];
// This balances out the dispatch_group_enter operation we did right before we enqueued this
dispatch_group_leave(group);
});
});
// Second verse, same as the first
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
NSDictionary* x = [self getDataWithPlatform:@"xboxone"];
dispatch_async(localDictWriteQueue, ^{
[localDict addEntriesFromDictionary: x];
dispatch_group_leave(group);
});
});
// Third verse, same as the first
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
NSDictionary* x = [self getDataWithPlatform:@"pc"];
dispatch_async(localDictWriteQueue, ^{
[localDict addEntriesFromDictionary: x];
dispatch_group_leave(group);
});
});
// Then set up the block we want to run at the end... use main queue because it updates UI.
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Update self.releasesDict all at once, on the main thread
// Note: we do not need to do this read of localDict on localDictWriteQueue because if this block is executing, we know (semantically) that all possible
// write operations have already completed, and that no other writes to localDict are possible because it's local to this method call.
self.releasesDict = localDict;
// Same idea
self.releasesArr = [self.releasesDict allKeys];
// Update UI based on state changes to self.
[self.tableView reloadData];
[self.activityInd stopAnimating];
});
謝謝UA很多,現在工作 – pluck
這不是安全地調用'addEntriesFromDictionary:'從(可能)多個併發線程。 – ipmcc