31
votes

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.

10
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
@benhameen Yes, I've only tested this on my iPhone 6.chris P

10 Answers

20
votes

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.

19
votes

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() 
    }
    
13
votes

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()
        }
    }
7
votes

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()
    })
}
3
votes

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
votes

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];
  });
}
2
votes

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.

0
votes

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.

0
votes

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

For further details: UISearchBar not showing keyboard when tapped

0
votes
-(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];
}