0

I want to allow the user to enter some notes in a UITextView before closing an app. But he/she might not enter anything or he/she might enter some text and then stop and do nothing for a long time. In either of those cases I want to close the UITextView, save some stuff, and exit the app. How do I detect that the user didn't entered anything for a certain number of seconds?

I tried to dispatch a function after a wait time

static int idleSeconds = 8;

self.noteDoneTime = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * idleSeconds);
dispatch_after(self.noteDoneTime, dispatch_get_main_queue(), ^{ [self endNoteRequest]; });

but every time the user changes the text renew the dispatch time:

- (void)textViewDidChange:(UITextView *)textView {
    if (textView == self.noteView) {
        self.noteDoneTime = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * idleSeconds);
    }
}

But that doesn't work because the dispatch time doesn't get updated after it is initially set, so the method 'endNoteRequest' runs even though the user is continuing to edit the text. I think I need to cancel the dispatch request and issue a new one but how can I do that?

Or is there some other approach to an idle timeout that actually works?

RobertL
  • 14,214
  • 11
  • 38
  • 44

1 Answers1

1

I do something just like this in a game app, where I penalize the user for every 10 seconds that elapses without the user's making any game move. It's like a "shot clock" in basketball, resetting after every shot.

It's easiest to do this with an NSTimer, because now you have an object that you can keep a reference to (e.g. an instance property). When the user types something, you invalidate the timer and set your reference to nil. Now it's gone! Now make a new one and set the reference to it. And so on.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks. I thought of that but I saw somewhere in the documentation that NSTimers are energy hungry and should be used only as a last resort, and that we should use dispatch methods instead. But maybe NSTimer is the only way. I'd really like to find a way to cancel a dispatch request. I'll wait for a while to see if anyone answers with information about cancelling a dispatch request, or updating the time it fires. – RobertL Nov 16 '15 at 22:44
  • I just now saw question 15005452 which looks like a way to reschedule a dispatch request. I'll look into that later tonight. – RobertL Nov 16 '15 at 22:50
  • I have a cancelable dispatch timer class here: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk1ch12p499timerLeaker2/ch12p325NotificationLeaker/CancelableTimer.swift but I think the "energy hungry" objection to NSTimer is nonsense. – matt Nov 16 '15 at 23:39
  • Your cancelable dispatch timer works very nicely! Thank you. I'm accepting your answer because of the cancelable timer. – RobertL Nov 17 '15 at 04:22