How does UISearchController work?
Asked Answered
S

1

6

How does UISearchController do everything it does?

  • How does it transform the UISearchBar into a navigation-bar-like view?
  • How does it put the UISearchBar into another view hierarchy and restore it later?
  • How does it do all this using the UIViewController presentation API?
  • How does it only cover the presenting view controller’s view even on iPhone where all presented view controllers are fullscreen?

Can I make my own UISearchController without using private APIs?

Selfexamination answered 20/3, 2015 at 23:11 Comment(0)
A
1

UISearchController creates a UISearchBar and in its internal _connectSearchBar method it calls a private method on UISearchBar _setSearchController. Then in the UISearchBar's internal event methods, e.g. _searchFieldBeginEditing it first calls its public delegate method and then [__searchController _searchBarTextDidBeginEditing:] to allow the controller to also process the event. This is what enables the feature "you free to become the UISearchBar's delegate".

Similarly, in UISearchBar's text field begin editing it calls UISearchController's _searchBarTextDidBeginEditing which calls _performAutomaticPresentation which uses the transition coordinator to animate the presentation.

In the UISearchBar's didMoveToSuperView it calls [__searchController _searchBarSuperviewChanged] which first checks if its searchBar has been put on a UITableView and if so it configures its background colours, insets etc. for viewing.

Yes you could architect this all yourself, but not by subclassing UISearchBar as you'd do in Java, instead of inheritance which can get complex use ObjC's delegation pattern which enables a flatter class hierarchy. E.g. you'd have a controller class that take a UISearchBar in its init method, sets itself as its delegate, then uses delegate forwarding to allow the existing delegate methods to still get called to the outside public delegate. Here is an example except for a table view:

- (instancetype)initWithTableView:(UITableView *)tableView{
    self = [super init];
    if (self) {
        tableView.delegate = self;
        _tableView = tableView;
    }
    return self;
}

- (id)forwardingTargetForSelector:(SEL)aSelector{
    if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
        if([self.tableViewDelgate respondsToSelector:aSelector]){
            return self.tableViewDelgate;
        }
    }
    return [super forwardingTargetForSelector:aSelector];
}

-(void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath{
    if([self.tableViewDelgate respondsToSelector:_cmd]){
        return [self.tableViewDelgate tableView:tableView didEndEditingRowAtIndexPath:indexPath];
    }
    [self performSelector:@selector(updateSelectionForCurrentVisibleDetailItem) withObject:nil afterDelay:0];
}

The point of this pattern is subclasses of your controller are no longer required to call super to ensure everything still works as expected without the programmer being required to call super. Also it makes for much more reusable classes since it can work with any kind of search bar.

Augustina answered 25/10, 2018 at 16:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.