Tengo una pregunta acerca de la seguridad de rosca del siguiente ejemplo de código de Apple (de GameKit guía de programación)Modificar objeto mutable en el manejador de finalización
Esta es cargar los logros del centro de juego y guardarlo localmente:
Paso 1) Agregue una propiedad de diccionario mutable a su clase que reporte logros. Este diccionario almacena la colección de objetos de logro.
@property(nonatomic, retain) NSMutableDictionary *achievementsDictionary;
Paso 2) Inicialice el diccionario de logros.
achievementsDictionary = [[NSMutableDictionary alloc] init];
Paso 3) Modifique el código que carga los datos de rendimiento para agregar los objetos de logro al diccionario.
{
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{
if (error == nil)
{
for (GKAchievement* achievement in achievements)
[achievementsDictionary setObject: achievement forKey: achievement.identifier];
}
}];
Mi pregunta es la siguiente - achievementsDictionary objeto está siendo modificado en el manejador de terminación, sin ningún tipo de cerraduras tipo. ¿Está permitido esto porque los controladores de finalización son un bloque de trabajo que iOS garantizará que se ejecute como unidad en el hilo principal? Y nunca se encuentra con problemas de seguridad de hilo?
En otro código de ejemplo de Apple (GKTapper), esta parte se maneja de manera diferente:
@property (retain) NSMutableDictionary* earnedAchievementCache; // note this is atomic
A continuación, en el controlador:
[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;
}
}];
Entonces, ¿por el estilo diferente, y es una manera más correcta ¿que el otro?
gracias Jeremy. También estaba cuestionando sobre los controladores de finalización de bloque en general. Si la documentación no indica explícitamente dónde se llama al controlador de finalización, ¿es seguro suponer que no se llama en el hilo principal? Si se especifica que se llame desde la cola principal, entonces es seguro hacer algo dentro sin preocuparse por la seguridad del hilo (suponiendo que todos los accesos son del hilo principal o del controlador compl llamado en la cola principal). –
Si no especifica que su bloque será llamado en la cola/hilo principal, entonces debe tomar sus propias medidas para asegurarse de que así sea, si eso es lo que necesita. En realidad, se podría invocar en el hilo principal, pero en ese punto, ese hecho es un detalle de implementación, no parte del contrato de API, y podría cambiar sin previo aviso. Si se especifica que se llame desde la cola principal, puede aprovecharlo al máximo. –
Una última pregunta entonces - si cambio el manejador de la primera finalización para usar dispatch_async (dispatch_get_main_queue(),^{for (GKAchievement * logro en los logros) [achievementsDictionary setObject: achievement forKey: achievement.identifier];});) will this ¿El código también es seguro? Recuerdo haber leído algo sobre que esto no era seguro. –