Question d’entretien chez Meta

iOS developers have a "dispatch_after(when, queue, block)" Grand Central Dispatch (GCD) function they can utilize but once it's set up, these calls can not be easily cancelled. Describe how you might implement a more convenient version of this named "cancellable_dispatch_after"

Réponses aux questions d'entretien

Utilisateur anonyme

14 janv. 2016

If we create an object called BoolNumber, e.g.: class BoolNumber : NSObject { @property (readwrite) Bool boolValue; } We can return it from our cancellable_dispatch_after method like so: - (BoolNumber *) cancellable_dispatch_after(when, queue, block) { BoolNumber *cancelState = [[BoolNumber alloc] init]; // the newBlock only runs after "when" and only if the cancelState bool value is set to false newBlock = ^{ if ( cancelState.boolValue == NO) block() }; dispatch_after(when, queue, newBlock); return cancelState; } So anybody calling this API will have a BoolNumber object which can cancel the block from running anytime during the "when" waiting period.

7

Utilisateur anonyme

20 oct. 2016

Wrapping the intended block is the way to go: @interface CancellationToken : NSObject -(void)cancel; @end @interface CancellationToken () @property BOOL cancelled; @end @implementation CancellationToken -(void)cancel { self.cancelled = @YES; } @end CancellationToken *cancellable_dispatch_after(dispatch_time_t time, dispatch_queue_t queue, dispatch_block_t block) { __block CancellationToken *token = [CancellationToken new]; dispatch_block_t wrapper = ^{ if (!token.cancelled) { block(); } }; dispatch_after(time, queue, wrapper); return token; } Use thusly: CancellationToken *token = cancellable_dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 15*NSEC_PER_SEC), q, ^{ NSLog(@"Here"); }); [token cancel];

2

Utilisateur anonyme

22 nov. 2016

Just use create a block a cancel using dispath_block_cancel(...)` dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"I'm an alert" message:@"done" preferredStyle:UIAlertControllerStyleAlert]; [self presentViewController:alert animated:YES completion:nil]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), block); dispatch_block_cancel(block); // Canceling the block

1

Utilisateur anonyme

24 mai 2016

You can make assosiation with block (pay attentions to block copy and retain cycle) -(NSObject *)getAssosiation:(dispatch_block_t)block { return objc_getAssociatedObject(block, @selector(getAssosiation:)); } -(void)setAssosiation:(dispatch_block_t)block { objc_setAssociatedObject(block, @selector(getAssosiation:), [NSObject new], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)cancelBlock:(dispatch_block_t)block { [self setAssosiation:block]; } -(dispatch_block_t) dispatch_after_with_cancel:(NSTimeInterval) delay for:(dispatch_block_t) block { dispatch_block_t cancellable = ^{ if (![self getAssosiation:block]) { block(); } }; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ cancellable(); }); return cancellable; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. dispatch_block_t block = ^{ NSLog(@"test"); }; [self dispatch_after_with_cancel:5 for:block]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self cancelBlock:block]; }); }

1

Utilisateur anonyme

20 déc. 2016

Create a function that returns a block which can be used to cancel the operation: dispatch_block_t cancellable_dispatch_after(dispatch_time_t time, dispatch_queue_t queue, dispatch_block_t block) { __block BOOL cancelled = NO; dispatch_after(time, queue, ^{ if (cancelled) return; block(); }); return ^{ cancelled = YES; }; } Usage: dispatch_block_t cancelOperation = cancellable_dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"Dispatched"); }); cancelOperation();

Utilisateur anonyme

18 sept. 2017

I don't understand why we would need so complicated solution. This simple solution just works fine for me: var pleaseCancel = false func call() { DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .seconds(4)) { print("in the block") if !pleaseCancel { print("the block's not cancelled") } } } call() pleaseCancel = true