Je joue actuellement avec Grand Central Dispatch et ai découvert une classe appelée DispatchWorkItem
. La documentation semble un peu incomplète, je ne suis donc pas sûre de l'utiliser correctement. J'ai créé l'extrait suivant et j'attendais quelque chose de différent. Je m'attendais à ce que l'article soit annulé après avoir appelé cancel
dessus. Mais l'itération continue pour une raison quelconque. Des idées que je fais mal? Le code semble bien pour moi.
@IBAction func testDispatchItems() {
let queue = DispatchQueue.global(attributes:.qosUserInitiated)
let item = DispatchWorkItem { [weak self] in
for i in 0...10000000 {
print(i)
self?.heavyWork()
}
}
queue.async(execute: item)
queue.after(walltime: .now() + 2) {
item.cancel()
}
}
GCD n'effectue pas d'annulations préemptives. Par conséquent, pour arrêter un élément de travail qui a déjà commencé, vous devez tester vous-même les annulations. Dans Swift, cancel
the DispatchWorkItem
. En Objective-C, appelez dispatch_block_cancel
sur le bloc que vous avez créé avec dispatch_block_create
. Vous pouvez ensuite vérifier si/a été annulé ou non avec isCancelled
dans Swift (connu sous le nom de dispatch_block_testcancel
dans Objective-C).
func testDispatchItems() {
let queue = DispatchQueue.global()
var item: DispatchWorkItem!
// create work item
item = DispatchWorkItem { [weak self] in
for i in 0 ... 10_000_000 {
if item.isCancelled { break }
print(i)
self?.heavyWork()
}
item = nil // resolve strong reference cycle
}
// start it
queue.async(execute: item)
// after five seconds, stop it if it hasn't already
queue.asyncAfter(deadline: .now() + 5) { [weak item] in
item?.cancel()
}
}
Ou, en Objective-C:
- (void)testDispatchItem {
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
static dispatch_block_t block = nil; // either static or property
__weak typeof(self) weakSelf = self;
block = dispatch_block_create(0, ^{
for (long i = 0; i < 10000000; i++) {
if (dispatch_block_testcancel(block)) { break; }
NSLog(@"%ld", i);
[weakSelf heavyWork];
}
block = nil;
});
// start it
dispatch_async(queue, block);
// after five seconds, stop it if it hasn't already
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (block) { dispatch_block_cancel(block); }
});
}
Il n'y a pas d'API asynchrone où appeler une méthode "Cancel" annulera une opération en cours. Dans tous les cas, une méthode "Annuler" fera quelque chose pour que l'opération puisse savoir si elle est annulée, et l'opération doit vérifier cela de temps en temps, puis cesser de travailler davantage par elle-même.
Je ne connais pas l'API en question, mais ce serait généralement quelque chose comme:
for i in 0...10000000 {
if (self?.cancelled)
break;
print(i)
self?.heavyWork()
}