I found a much better solution to this issue, and it seems to work perfectly on iOS 6 and 7. While it is still a hack, its a much cleaner and future proof hack than the above. The other solutions do not work consistently and prevent some UISearchDisplayDelegate methods from ever firing! Further I had complex insetting issues which I could not resolve with the above methods. The main issue with the other solutions is that they seriously confuse the internals of the UISearchDisplayController. My solution is based on the observation that UISearchDisplayContoller is a UISearchbarDelegate and that the automatic undimming & showing of results table can be triggered by simulating a keypress in the search field! So:
- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
if ([controller respondsToSelector: @selector(searchBar:textDidChange:)])
[(id<UISearchBarDelegate>)controller searchBar: controller.searchBar textDidChange: @" "];
}
This code is future proof against crashing by checking it responds to the UISearchbarDelegate method, and sends space @" " to trick the UISearchDisplayController into thinking user has typed a letter.
Now if the user types something and then erases it, the table will dim again. The other solutions try to work around this by doing something in the searchDisplayController:didHideSearchResultsTableView: method. But this doesn't make sense to me, as surely when you cancel the search it will need to truly hide your results table and you may need to run code in this case. My solution for this part is to subclass (note you could probably use a Method Swizzled Category to make it work everywhere if needed in your project):
// privately declare protocol to suppress compiler warning
@interface UISearchDisplayController (Super) <UISearchBarDelegate>
@end
// subclass to change behavior
@interface GMSearchDisplayController : UISearchDisplayController
@end
@implementation GMSearchDisplayController
- (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchString
{
if (searchString.length == 0)
searchString = @" ";
if ([super respondsToSelector: @selector(searchBar:textDidChange:)])
[super searchBar: searchBar textDidChange: searchString];
}
@end
This code works by intercepting the textDidChange delegate method and changing nil or empty strings in to space string @" " preventing the normal hiding/dimming that occurs on an empty search bar. If you are using this second bit of code, then you could modify the first bit to pass a nil instead of @" " as this second bit will do the needed conversion to @" " for you.
In my own project, I needed to handle the case that user does type a space, so instead of @" " above I used a defined token:
// arbitrary token used internally
#define SEARCH_PRELOAD_CONDITIONAL @"_#preresults#_"
And then handle it internally by converting it back to nil string:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL])
searchString = nil;
}
Enjoy! :)