32

I've spent quite a bit of time searching online and talking to other developers about this issue to no avail. The exact issue is described in this SO post (Focus on the UISearchBar but the keyboard not appear), although it's many years old.

I recently switched from using the deprecated UISearchDisplayController and UISearchBar in IB, and switched over to UISearchController via the code for iOS8.

The problem I'm getting however, is that focus is assigned correctly (you can tell because the cancel button animates to the right of the search bar after the view loads), however the keyboard does not show up.

Here's the code that I have.

.h

@property (nonatomic, strong) UISearchController *searchController;

.m

- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    [self initializeSearchController];
    ....
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.searchController setActive:YES];
    [self.searchController.searchBar becomeFirstResponder];
}

- (void)initializeSearchController {
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.delegate = self;
    self.searchController.searchBar.delegate = self;
    [self.searchController.searchBar sizeToFit];

    [self.tableView setTableHeaderView:self.searchController.searchBar];
    self.definesPresentationContext = YES;
}

The things I've tried so far.

  • I've tried calling becomeFirstResponder on a 0.2 second delay, as suggested in another SO post.

  • I've set a breakpoint in viewDidAppear, and verified that both self.searchController and self.searchController.searchBar are both valid objects, neither nil.

  • I've tried conforming to the UISearchControllerDelegate and using the following snippet of code

here:

- (void)didPresentSearchController:(UISearchController *)searchController {
    //no matter what code I put in here to becomeFirstResponder, it doesn't
    //matter because this is never called, despite setting the     
    //self.searchController.delegate = self AND 
    //self.searchController.searchBar.delegate = self.
}
  • I've created a new view from scratch in storyboards, and segued to that one instead, to make sure I didn't have some old searchBar remnant in my view. This did not work either.

  • I've only tested this on a real device (iPhone 6), and it's not a simulator issue of not showing the keyboard.

I'm out of ideas, and I've seen every question and answer related to this one the web. Nothing is working.

To clarify again what's going on, the searchBar correctly becomes the first responder, the cancel button to the right of it animates onscreen proving this, but the keyboard does not appear and the cursor does not blink in the searchBar.

chris P
  • 6,359
  • 11
  • 40
  • 84
  • 1
    Have you tested this on an actual device? If this problem is occurring on the Simulator, try pressing ⌘K (command-k) to bring up the keyboard. – benhameen May 29 '15 at 06:10
  • 1
    @benhameen Yes, I've only tested this on my iPhone 6. – chris P May 29 '15 at 06:12

10 Answers10

21

Your code looks ok. What you are describing isn't normal behaviour. The first thing you can do is to create a new project with just the UISearchController functionality and see how it goes. You can edit your question with it so we'll have a better view.

There's a good example on how to implement UISearchController here: Sample-UISearchController

Adding:

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.searchController.searchBar becomeFirstResponder];
}

to MasterViewController_TableResults.m gave the expected results and the keyboard popped up on launch on an iPad & iPhone with iOS 8.3.

You can go over that project and see what you did differently,

Edit:

Apparently if [self.searchController setActive:YES] is called before becomeFirstResponder the keyboard won't show. I wonder if that's a bug or not.

Segev
  • 19,035
  • 12
  • 80
  • 152
  • Note the question is not about the (deprecated) `UISearchDisplayController` – Felix Jun 29 '15 at 09:22
  • The project in the link is using `UISearchController`. sorry for the typo. (fixed) – Segev Jun 29 '15 at 10:26
  • 1
    It worked! The strange thing is that the keyboard does not appear, when [self.searchController setActive:YES] is called before that, like the code in the question. – Felix Jun 29 '15 at 10:42
  • Interesting. I wonder if that's a bug or not. Glad you found the issue. I'll edit my answer with your findings. – Segev Jun 29 '15 at 10:48
  • I've tried putting the call to set the search controller active after the call to make the search bar become the first responder. Still not working for me. I am using this in conjunction with a navigation controller. Not sure if that is the difference. – Jeremy Hicks Sep 25 '15 at 21:34
19

Had the same annoying issue. You would think that by setting the SearchController as active would both present the the search controller and the keyboard. Unfortunately, it only does the first part.

My solution

  • in viewDidAppear make the Search Controller active:

    override func viewDidAppear(animated: Bool) {
      super.viewDidAppear(animated)
      resultSearchController.active = true 
    }
    
  • once it is active, in didPresentSearchController make as first responder

    func didPresentSearchController(searchController: UISearchController) {
      searchController.searchBar.becomeFirstResponder() 
    }
    
Onato
  • 9,916
  • 5
  • 46
  • 54
emn.mun
  • 437
  • 4
  • 12
  • 6
    does not work for me. didPresentSearchController is called, but keyboard does not appear. – Felix Jul 03 '15 at 20:35
  • It worked for me, though the second code sample seems to have had a small typo (I'll submit an edit for it). I'd rather the controller became active and the keyboard appeared at the same time, but this will do for now. – Garrett Albright Jul 04 '15 at 06:24
  • Works for me on iOS9, too. Very annoying problem. I was on the edge of giving up. Thanks. – AXE Sep 11 '15 at 21:22
  • 7
    Does any know why this doesn't work on iOS9 when the search bar is in the navigation bar? – Valentin Sep 21 '15 at 04:56
  • 9
    @Valentin, this works for me only when I make the searchbar the first responder on the main thread: `dispatch_async(dispatch_get_main_queue(), { searchController.searchBar.becomeFirstResponder() })` – vinsanity555 Jan 08 '16 at 00:04
13

Swift 3.0 (iOS 10) working solution:

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        searchController.isActive = true
        DispatchQueue.main.async { [unowned self] in
            self.searchController.searchBar.becomeFirstResponder()
        }
    }
Tendai Moffatt
  • 236
  • 2
  • 4
7

On iOS 9 I've found its sufficient to delay becomeFirstResponder() to the next run loop:

func focusSearchField() {
    searchController?.active = true

    // skipping to the next run loop is required, otherwise the keyboard does not appear
    dispatch_async(dispatch_get_main_queue(), { [weak self] in
        self?.searchController?.searchBar.becomeFirstResponder()
    })
}
jszumski
  • 7,430
  • 11
  • 40
  • 53
  • The only thing that worked for me on iOS 9. You can use `[unowed self]` and get read of the unwrapping of `self`. IMHO it is cleaner & safe here. – tonymontana Jun 08 '16 at 19:49
3

Working Solution:-

Don't use [self.searchController setActive:YES] before becomeFirstResponder.

- (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
       // [self.searchController setActive:YES];
        [self.searchController.searchBar becomeFirstResponder];
     });
 });
}
2

The solution that will work is as follows :

1.Override ViewDidLayoutSubviews in the view controller in which you are showing UISearchController

2.Override ViewDidLayoutSubviews and inside it make search bar first responder.

Tested it on iOS > 9.0

Caution : Put a null check before making it First responder as follows

if((searchController != null)&&(searchController.SearchBar != null))
            searchController.SearchBar.BecomeFirstResponder();

This is because ViewDidLayoutSubviews also gets called when cancel button is pressed.

This worked for me in Xamarin.

Abha
  • 1,032
  • 1
  • 13
  • 36
aas
  • 39
  • 4
2

In iOS 10, I had to run the code in delegate method on main thread. First I set the active to YES in viewDidAppear,

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
      [self.searchController setActive:YES];
}

and then in the delegate method:

- (void)didPresentSearchController:(UISearchController *)searchController
{
  dispatch_async(dispatch_get_main_queue(), ^{
  [searchController.searchBar becomeFirstResponder];
  });
}
Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109
0

I had trouble with an UISearchBar not displaying the keyboard when doing

[searchBar becomeFirstResponder];

By searching on the net, i found this thread on the Apple developer website that helped me to discover that the keyboard won't open if you don't have a keyWindow.

The application i work on do something like this :

  1. Window A (KeyWindow)
  2. do some things
  3. open Window B (KeyWindow)
  4. do some things
  5. close Window B (resign KeyWindow)

I just had to do

[[[[UIApplication sharedApplication] windows] firstObject] makeKeyWindow];

after the resigning of window B and no more trouble with the keyboard.

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
0

This might also be related to Simulator Settings. Just disable Hardware -> Keyboard -> "Connect Hardware Keyboard" .

For further details: UISearchBar not showing keyboard when tapped

Community
  • 1
  • 1
Özgür
  • 8,077
  • 2
  • 68
  • 66
0
-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.searchController setActive:YES];
}

//and then in the delegate method:

- (void)didPresentSearchController:(UISearchController *)searchController
{
  dispatch_async(dispatch_get_main_queue(), ^{
  [searchController.searchBar becomeFirstResponder];
  });
}

//The above works for me in addition to this I had to add:
-(void)viewWillDisappear:(BOOL)animated {
    [searchController setActive:NO];
}