iOS: Perform action after time while user is interacting / scrolling
-
18-06-2021 - |
Frage
I'm trying to get my application to perform an action after a delay, but it will have to be done WHILE the user is interacting with/scrolling on a UIScrollView
.
I'm not sure why neither performSelector:withObject:afterDelay
or scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
will fire. Is it because they're on a background thread?
Any suggestions or help?
Lösung
Both NSTimer
and performSelector:withObject:afterDelay:
by default only fire in the normal run loop mode. When scrolling, the run loop is in event tracking mode.
You have to schedule your timed action in all common modes:
NSTimer *timer = [NSTimer timerWithTimeInterval:0.016 target:self selector:@selector(fire:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
or
[self performSelector:@selector(fire:) withObject:nil afterDelay:1.0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
There's also the dedicated NSEventTrackingRunLoopMode
.
Andere Tipps
Be sure the delayed trigger happens on the NSRunLoopCommonModes
. The default is NSDefaultRunLoopMode
which won't get messages while e.g. scrolling.
[self performSelector:@selector(fire:) withObject:nil afterDelay:2.0 inModes:@[NSRunLoopCommonModes]];
Alternatively you can use GCD
which also behaves the same way (not sure which runloop mode it uses)
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
<#code to be executed on the main queue after delay#>
});
For Swift:
performSelector(#selector(fire:), withObject: sender, afterDelay: 1.0, inModes: [NSRunLoopCommonModes])