UITableViewで一覧表示と検索機能付き。よくあるUIのパターンです。この実現を容易に行うことができるのがUISearchControllerです。

サンプルを作りましたので、これを見ながらUISearchControllerの使い方を解説していきます。

stack3/STSearchControllerSample

STGrapesViewControllerクラス

ぶどうの一覧をUITableViewで表示します。
検索機能があり検索入力すると代わりにSTGrapeSearchResultsControllerを表示します。

STGrapeSearchResultsControllerクラス

ユーザーが入力した文字列を含むぶどう一覧をUITableViewで表示します。

STGrapesViewControllerの実装

プロパティの宣言。

// ぶどう一覧表示するUITableView
@property (weak, nonatomic) IBOutlet UITableView *tableView;
// ぶどう名を格納する配列
@property (strong, nonatomic) NSMutableArray *grapes;
// UISearchController
@property (strong, nonatomic) UISearchController *searchController;
// STGrapeSearchResultsController(検索結果表示用ViewController)
@property (strong, nonatomic) STGrapeSearchResultsController *searchResultsController;

viewDidLoadの実装。_grapesにぶどう名を格納します。

_grapes = [NSMutableArray arrayWithCapacity:100];
[_grapes addObject:@"Cabernet Sauvignon"];
[_grapes addObject:@"Merlot"];
[_grapes addObject:@"Pino Noir"];
[_grapes addObject:@"Chardonnay"];
[_grapes addObject:@"Sauvignon Blanc"];
[_grapes addObject:@"Riesling"];

StorybordからSTGrapeSearchResultsControllerを生成する。

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
_searchResultsController = [sb instantiateViewControllerWithIdentifier:@"STGrapeSearchResultsController"];
_searchResultsController.allGrapes = _grapes;

UISearchControllerを生成する。

// 検索結果表示用ViewControllerとして_searchResultsControllerを渡す
_searchController = [[UISearchController alloc] initWithSearchResultsController:_searchResultsController];
// 検索入力用のUISearchBarの高さを指定。
_searchController.searchBar.frame = CGRectMake(0, 0, self.view.bounds.size.width, 44);
_searchController.searchBar.returnKeyType = UIReturnKeyDone;
_searchController.searchBar.placeholder = @"Search";
// 検索入力内容が変更されたことを受け取る
_searchController.searchBar.delegate = self;
// UISearchControllerDelegateは、あまり使うことはなさそう
//_searchController.delegate = self;

UITableViewの初期化。

[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
_tableView.dataSource = self;
// UISearchControllerとUITableViewをひもづける
_tableView.tableHeaderView = _searchController.searchBar;

UITableView#tableHeaderViewにUISearchController#searchBarを設定することで一覧の上端に検索入力が表示されるようになります。

UITableViewDataSourceを実装して_grapesからUITableViewCellに表示させる。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _grapes.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *row = [_grapes objectAtIndex:indexPath.row];

    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    cell.textLabel.text = row;

    return cell;
}

UISearchBarDelegateの検索文字が変更になった時、STGrapeSearchResultsController#queryを呼び出し、検索条件が変わったことを伝える。

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    [_searchResultsController query:searchText];
}

STGrapeSearchResultsControllerの実装

プロパティの宣言。

@property (strong, nonatomic) NSArray *allGrapes;
@property (strong, nonatomic, readonly) NSMutableArray *searchedGrapes;
@property (weak, nonatomic) IBOutlet UITableView *tableView;

※ tableViewは外部公開する必要がないので*.hではなく*.mの方に宣言してます。細かい話ですが・・・

viewDidLoadの実装。

- (void)viewDidLoad {
    [super viewDidLoad];
    // 検索結果を格納する配列
    _searchedGrapes = [NSMutableArray arrayWithCapacity:10];
    // CellとDataSourceのいつものおまじない
    [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    _tableView.dataSource = self;
}

入力した検索文字がqueryにわたってくるので、それに応じて_allGrapesから条件に一致するものを_searchedGrapesに移す。

- (void)query:(NSString *)query {
    [_searchedGrapes removeAllObjects];
    for (NSString *grape in _allGrapes) {
        NSRange range = [grape rangeOfString:query];
        if (range.location != NSNotFound) {
            [_searchedGrapes addObject:grape];
        }
    }
    [_tableView reloadData];
}

_searchedGrapesを元に一覧表示。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _searchedGrapes.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *row = [_searchedGrapes objectAtIndex:indexPath.row];
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    cell.textLabel.text = row;
    return cell;
}

以上で説明は終わりです。記事は長くなりましたが、実際やっている内容はそれほど難しくなく、UIもプリインストールのメールアプリのように自然な感じになります。