Muszę najpierw zauważyć, że nie jest to dobrą rzeczą w innych sytuacjach niż testowanie; nawet wtedy postępuj ostrożnie - AliSoftware dostarcza kilka szczegółów i przykładowy kod w komentarzach poniżej. Zobacz także interesujące odpowiedzi na Can I declare a dispatch_once_t
predicate as a member variable instead of static?, w tym kilka ważnych informacji from the horse's mouth.
dispatch_once_t
to typedef
d long
. Jego wartość false wynosi 0. Jeśli zresetujesz tę flagę do 0, dispatch_once()
zostanie uruchomione ponownie. Twoim problemem jest "po prostu", jak zmienić wartość zmiennej statycznej z innej jednostki kompilacji. Do tego, myślę, że trzeba hak testowy debug/jednostki, tak jak poniżej:
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
(Można też przenieść once_token
do pliku . poziom i zmienić go bezpośrednio)
Trying to uwagę:
#import <Foundation/Foundation.h>
#import "MakeWhoopie.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
makeWhoopie();
makeWhoopie();
resetDispatchOnce();
makeWhoopie();
}
return 0;
}
Wyniki w:
2012-06-07 18: 45: 28,134 ResetDispatchOnce [8628: 403] To co masz, ludzie.
2012-06-07 18: 45: 28.163 ResetDispatchOnce [8628: 403] Dokonywanie whoopie.
2012-06-07 18: 45: 28.164 ResetDispatchOnce [8628: 403] Dokonywanie whoopie.
2012-06-07 18: 45: 28.165 ResetDispatchOnce [8628: 403] To właśnie dostajesz, ludzie.
2012-06-07 18: 45: 28.165 ResetDispatchOnce [8628: 403] Dokonywanie whoopie.
Punkt 'dispatch_once' oznacza, że jest bezpieczny dla wątków. Problem przez ustawienie '* once_token_debug = 0' w ten sposób jest taki, że w ogóle nie jest bezpieczny w wątku, w przypadku gdy inny wątek używa' dispatch_once (& onceToken, ...) 'podczas samodzielnego ustawiania' OnceToken'. Jak możemy zapobiec takiemu problemowi? – AliSoftware
@AliSoftware: Scenariuszem w pytaniu jest testowanie jednostkowe i jest to jedyne użycie, które proponuję dla tej procedury. Token zostaje zresetowany _tutaj_, aby utworzyć czysty plan, tak jak zostałby utworzony pomiędzy przebiegami większego programu. Nawlekanie nie stanowi problemu, ponieważ program nie działa między testami. –
Rozumiałem to, ale każdy musi być tego świadomy i nie być kuszonym, by używać go w inny sposób niż gdzie indziej.I może być kilka przypadków nawet w testach jednostkowych, że nie jest to bezpieczne dla wątków, szczególnie jeśli źle zakodujemy test i wykonamy asynchroniczne akcje, które będą kontynuowane nawet po zakończeniu testów (jak wywołanie 'dispatch_after (10s,^{/ * sthg, który używa sharedInstance * /} 'jeśli test osiągnie swój limit czasu, zakończy się niepowodzeniem i zostanie zatrzymany i osiągnie' tearDown', ale blok korzystający z metody sharedInstance będzie nadal wysyłany w najbliższej przyszłości ... po usunięciu łzy – AliSoftware