Debo observar primero que esto no es algo bueno que hacer en cualquier situación que no sea la prueba; incluso entonces, proceda con cuidado: AliSoftware proporciona algunos detalles y código de ejemplo en los comentarios a continuación. Consulte también las respuestas interesantes en Can I declare a dispatch_once_t
predicate as a member variable instead of static?, incluida información importante from the horse's mouth.
dispatch_once_t
es un typedef
d long
. Su valor falso es 0. Si reinicia ese indicador a 0, dispatch_once()
se ejecutará nuevamente. Su problema es "solo" cómo cambiar el valor de una variable estática de otra unidad de compilación. Para esto, creo que es necesario un gancho de prueba de depuración/unidad, así:
MakeWhoopie.h
#import <Foundation/Foundation.h>
void makeWhoopie(void);
#ifdef DEBUG
void resetDispatchOnce(void);
#endif
MakeWhoopie.m
#include "MakeWhoopie.h"
static dispatch_once_t * once_token_debug;
void makeWhoopie(void)
{
static dispatch_once_t once_token;
once_token_debug = &once_token; // Store address of once_token
// to access it in debug function.
dispatch_once(&once_token, ^{
NSLog(@"That's what you get, folks.");
});
NSLog(@"Making whoopie.");
}
#ifdef DEBUG
void resetDispatchOnce(void)
{
*once_token_debug = 0;
}
#endif
(También podría mover once_token
hasta presentar . nivel y cambiarlo directamente)
intentar esto:
#import <Foundation/Foundation.h>
#import "MakeWhoopie.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
makeWhoopie();
makeWhoopie();
resetDispatchOnce();
makeWhoopie();
}
return 0;
}
Resultados: en
2012-06-07 18: 45: 28.134 ResetDispatchOnce [8628: 403] Eso es lo que se obtiene, amigos.
2012-06-07 18: 45: 28.163 ResetDispatchOnce [8628: 403] Haciendo whoopie.
2012-06-07 18: 45: 28.164 ResetDispatchOnce [8628: 403] Haciendo whoopie.
2012-06-07 18: 45: 28.165 ResetDispatchOnce [8628: 403] Eso es lo que obtienes, amigos.
2012-06-07 18: 45: 28.165 ResetDispatchOnce [8628: 403] Haciendo whoopie.
El objetivo de 'dispatch_once' es que es seguro para subprocesos. El problema al configurar '* once_token_debug = 0' de esta manera es que no es seguro para subprocesos en todos los casos en que otro subproceso usa' dispatch_once (& oneToken, ...) 'mientras configura el' onceToken' por usted mismo. ¿Cómo es que podemos evitar tal problema? – AliSoftware
@AliSoftware: El escenario en la pregunta es la prueba unitaria, y ese es el único uso que propongo para este procedimiento. El token se restablece _between_ tests, para crear una lista limpia tal como se crearía entre las ejecuciones del programa más grande. Enhebrar no es un problema porque el programa no se ejecuta entre pruebas. –
Entendí esto, pero todos deben ser conscientes de eso y no estar tentados a usar esto de una manera que no sea segura contra el hilo en otro lugar.Y puede haber algunos casos incluso en Pruebas unitarias que no sean seguros para subprocesos, especialmente si uno codifica mal su prueba y realiza acciones asíncronas que continúan ejecutándose incluso después de que finalizan las pruebas (como una llamada a 'dispatch_after (10s,^{/ * sthg que usa sharedInstance * /} 'si la prueba alcanza su tiempo de espera, fallará y se detendrá y llegará a' tearDown' pero el bloque que usa sharedInstance aún se enviará en un futuro próximo ... después de tearDown. – AliSoftware