4

The first time becomeFirstResponder gets called, it's slowish. Instruments measures about 160ms ... By the time it's done with loading everything it had to load in order to get the keyboard on screen, the keyboard just shows up! Killing most of the smooth animation.

The second time however, it's blazing fast! It takes just 2ms!

So, could I do this somehow?

nmdias
  • 3,888
  • 5
  • 36
  • 59
  • What is your `becomeFirstResponder` doing that is taking all the time!? – bbum Jul 22 '13 at 00:42
  • I've personally noted that the keyboard takes extra time if you have additional keyboards, specially the emoji one. I was testing the frame of the keyboard with the english, spanish, japanese, and emoji keyboards and I always noticed a big slowdown. – Can Jul 22 '13 at 01:03
  • Check out @Vadoff's answer here - http://stackoverflow.com/a/20436797/558575 – amergin Jan 17 '14 at 16:52

1 Answers1

2

Using GCD

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// heavy lifting here
    dispatch_async(dispatch_get_main_queue(), ^{
        [someTextField becomeFirstResponder];
    });
});

This wasn't initially working as expected, but it did after applying GCD to some "lifting" that was happening in the background. In my case, it was a scroling view

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// heavy lifting here
    dispatch_async(dispatch_get_main_queue(), ^{
        [_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    });
});
nmdias
  • 3,888
  • 5
  • 36
  • 59
  • 3
    The third version doesn't do anything beyond possibly delaying the `becomeFirstResponder` until the next pass through the event loop. All the work is still done on the main thread. The first solution is insanely fragile and ugly. The second solution seems to be a non-solution; it doesn't appear to really change anything. – bbum Jul 22 '13 at 00:40
  • The third solution makes sure it runs asynchronously. Doing the same on the lifting that I was doing on the background made sure none of them step on eaches toe. The result was a bit of delay, yes, but without compromising smoothness of the animation. I could no predict the amount of time needed to fire becomeFirstResponder, so this became a much more elegant solution. I will update the answer and remove solutions 1 and 2. – nmdias Jul 22 '13 at 00:53
  • 1
    You can't run something asynchronously on the main thread and *not block or delay the event loop*. If it solves the problem, it is because it is done in the next pass after the current through the main event loop; you could use `dispatch_after()` with a delay of 0.0 or `performSelector:withObject:afterDelay:0.0...` and get the same result without the extra block enqueue. (And, if that really does fix the problem, then... neat! Noted!) – bbum Jul 22 '13 at 05:06
  • Then in that case I'm still not sure why if fixes. I do this when I need to do 2 things at once, like touching and animating something at the same time. I guess this is not like scheduling threads then. performSelector after delay gave very diferrent results on diferent times. I will try dispatch_after(), but for now it's working like a charm ^^ – nmdias Jul 22 '13 at 12:11