Ho una domanda sulla sicurezza filo del seguente esempio di codice da parte di Apple (da guida alla programmazione GameKit)Modifica oggetto mutabile nel gestore di completamento
Questo è per caricare successi dal centro del gioco e salvarlo in locale:
Passaggio 1) Aggiungere una proprietà del dizionario mutabile alla classe che segnala i risultati. Questo dizionario memorizza la collezione di oggetti di successo.
@property(nonatomic, retain) NSMutableDictionary *achievementsDictionary;
Passaggio 2) Inizializzare il dizionario dei risultati.
achievementsDictionary = [[NSMutableDictionary alloc] init];
Passaggio 3) Modificare il codice che carica i dati di completamento carichi per aggiungere gli oggetti raggiungimento al dizionario.
{
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{
if (error == nil)
{
for (GKAchievement* achievement in achievements)
[achievementsDictionary setObject: achievement forKey: achievement.identifier];
}
}];
La mia domanda è la seguente - oggetto achievementsDictionary viene modificato nel gestore di completamento, senza serrature di sorta. Questo è permesso perché i gestori di completamento sono un blocco di lavoro che sarà garantito da iOS per essere eseguito come unità sul thread principale? E non incorrere mai in problemi di sicurezza del thread?
In un altro codice di esempio di Apple (GKTapper), questa parte viene gestita in modo diverso:
@property (retain) NSMutableDictionary* earnedAchievementCache; // note this is atomic
Poi nel gestore:
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
if(error == NULL)
{
NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement* score in scores)
{
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache= tempCache;
}
}];
Allora perché il diverso stile, ed è un modo più corretto rispetto agli altri?
grazie Jeremy. Mi sono anche interrogato sugli addetti al completamento dei blocchi in generale. Se la documentazione non dice esplicitamente dove viene chiamato il gestore di completamento, è sicuro assumere che non è chiamato nel thread principale? Se viene specificato che viene chiamato dalla coda principale, è sicuro fare qualsiasi cosa all'interno senza preoccuparsi della sicurezza dei thread (presupponendo che tutti gli accessi siano dal thread principale o dal gestore compl. Richiamato nella coda principale). –
Se non specifica che il blocco verrà chiamato sulla coda principale/thread, allora devi prendere le tue misure per assicurarti che sia, se è quello che ti serve. Potrebbe essere effettivamente chiamato sul thread principale, ma a quel punto, questo fatto è un dettaglio di implementazione, non parte del contratto API, e potrebbe cambiare senza preavviso. Se viene specificato per essere chiamato dalla coda principale, puoi trarne il massimo vantaggio. –
Un'ultima domanda quindi - se cambio il primo handler di completamento per usare dispatch_async (dispatch_get_main_queue(),^{per (GKAchievement * raggiungimento dei risultati) [achievementsDictionary setObject: achievement forKey: achievement.identifier];});) anche il codice è thread-safe? Ricordo di aver letto qualcosa su questo non essere sicuro .. –