Sometimes you put a delayed operation being a flag which you can clear to cancel. It might look like this:
- (void)primeOperation {
    self.flag = YES;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, someTimeInSecs * NSEC_PER_SEC), dispatch_get_main_queue(), ^() {
        if (self.flag) {
            self.flag = NO;
            //do something
        }
    });
}
But the problem with this approach is after if you clear the flag and set up the operation again soon enough, you will end up with running that operation twice:
- (void)doSomething {
    [self primeOperation];
    self.flag = NO;
    [self primeOperation];
}
One of the ways to work around this is to create an NSOperation subclass.
Alternatively, you can create a lightweight class that wraps around a BOOL:
@interface BoolWrapper: NSObject
@property(nonatomic) BOOL state;
+ (instancetype)wrapperWithBool:(BOOL)state;
@end
@implementation BoolWrapper
+ (instancetype)wrapperWithBool:(BOOL)state {
    BoolWrapper* result = [self new];
    result.state = state;
    return result;
}
@end
You can change your code so that flag is now an instance of BoolWrapper:
- (void)primeOperation {
    self.flag = [BoolWrapper wrapperWithBool:YES];
    BoolWrapper* previousFlag = self.flag;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, someTimeInSecs * NSEC_PER_SEC), dispatch_get_main_queue(), ^() {
        if (self.flag == previousFlag && self.flag.state) {
            self.flag = [BoolWrapper wrapperWithBool:NO];
            //do something
        }
    });
}
This will now work since the identity check self.flag == previousFlag takes care that we are referring to the same "operation".
.
.