近期学习过程中想模拟一下新浪微博“发现”界面。
我在storyboard中拖入一个UITableViewController,设置这个UITableViewController的TableView为Static Cells,然后加入了两个Section,每一个Section两行Cell。
接下来往这个TableView中拖入了一个UISearchBar and Search Display Controller,storyboard中的结构例如以下图:
然后在UITableViewController相应的 WBDiscoverTableViewController.m中实现相关的协议方法。代码例如以下:
#import "WBDiscoverTableViewController.h" @interface WBDiscoverTableViewController () @property ( weak , nonatomic ) IBOutlet UISearchBar *mySearchbar; @property ( nonatomic , strong ) NSArray *results; @property ( weak , nonatomic ) IBOutlet UITableViewCell *hotTopicsCell1; @property ( weak , nonatomic ) IBOutlet UITableViewCell *hotTopicsCell2; @property ( weak , nonatomic ) IBOutlet UITableViewCell *nearbyPeopleCell; @property ( weak , nonatomic ) IBOutlet UITableViewCell *nearbyWeiboCell; @end @implementation WBDiscoverTableViewController - ( void )viewDidLoad {
[super viewDidLoad];
static NSString *cellID = @"resultCell" ; [ self . searchDisplayController . searchResultsTableView registerClass :[ UITableViewCell class ] forCellReuseIdentifier :cellID]; } - ( void )viewWillAppear:( BOOL )animated { }
- ( void )searchWithString { switch ( self . mySearchbar . selectedScopeButtonIndex ) { case 0 : // 搜用户 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsUsersWithString : self . mySearchbar . text AndCount : 20 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; case 1 : // 搜学校 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsSchoolsWithString : self . mySearchbar . text AndCount : 20 AndType : 0 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; case 2 : // 搜公司 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsCompaniesWithString : self . mySearchbar . text AndCount : 20 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; default : break ; } }
#pragma mark UISearchBarDelegate
- ( void )searchBarSearchButtonClicked:( UISearchBar *)searchBar { [ self searchWithString ]; }
#pragma mark UISearchDisplayDelegate - ( void )searchDisplayControllerWillBeginSearch:( UISearchDisplayController *)controller { NSLog ( @"WillBeginSearch...." ); } - ( void )searchDisplayControllerDidBeginSearch:( UISearchDisplayController *)controller { NSLog ( @"DidBeginSearch...." ); } - ( void )searchDisplayControllerWillEndSearch:( UISearchDisplayController *)controller { NSLog ( @"WillEndSearch...." ); } - ( void )searchDisplayControllerDidEndSearch:( UISearchDisplayController *)controller { NSLog ( @"DidEndSearch...." ); } - ( BOOL )searchDisplayController:( UISearchDisplayController *)controller shouldReloadTableForSearchString:( NSString *)searchString { [ self searchWithString ]; return NO ; } - ( BOOL )searchDisplayController:( UISearchDisplayController *)controller shouldReloadTableForSearchScope:( NSInteger )searchOption { [ self searchWithString ]; return NO ; }
#pragma mark - Table view data source // 因为这个控制器既是原来的 WBDiscoverTableViewController 。又是 UISearchDisplayController 的 searchContentsController 。 //WBDiscoverTableViewController 的 tableView 和 searchResultsTableView 的 delegat 都指向这个对象( self )。 // 所以须要在回调中差别究竟是哪个 tableView - ( NSInteger )numberOfSectionsInTableView:( UITableView *)tableView { if (tableView == self . tableView ) { return 2 ; } else if (tableView == self . searchDisplayController . searchResultsTableView ){ return 1 ; } else return 0 ; } - ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section { if (tableView == self . tableView ) { return 2 ; } else if (tableView == self . searchDisplayController . searchResultsTableView ) { return self . results . count ; } else return 0 ; } - ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath { if (tableView == self . tableView ) { if (indexPath. section == 0 && indexPath. row == 0 ) { return self . hotTopicsCell1 ; } else if (indexPath. section == 0 && indexPath. row == 1 ) { return self . hotTopicsCell2 ; } else if (indexPath. section == 1 && indexPath. row == 0 ) { return self . nearbyPeopleCell ; } else { return self . nearbyWeiboCell ; } } else if (tableView == self . searchDisplayController . searchResultsTableView ) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"resultCell" ]; id result = self . results [indexPath. row ]; if ([result isMemberOfClass :[ WBSearchSuggestionsOfUsers class ]]) { WBSearchSuggestionsOfUsers * suggestion = result; cell. textLabel . text = suggestion. nickName ; cell. detailTextLabel . text = suggestion. followersCount ; } else if ([result isMemberOfClass :[ WBSearchSuggestionsOfSchools class ]]) { WBSearchSuggestionsOfSchools *suggestion = result; cell. textLabel . text = suggestion. schoolName ; cell. detailTextLabel . text = suggestion. location ; } else { WBSearchSuggestionsOfCompanies *suggestion = result; cell. textLabel . text = suggestion. suggestion ; } return cell; } else return nil ; }
- ( CGFloat )tableView:( UITableView *)tableView heightForHeaderInSection:( NSInteger )section { return 10 ; } - ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath { // UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; UIViewController *vc = [[ UIViewController alloc ] init ]; vc. view . backgroundColor = [ UIColor whiteColor ]; [ self . navigationController pushViewController :vc animated : YES ];
}
@end
当我在UISearchBar中输入keyword进行搜索。假设返回结果的数量( self . results . count)大于2的时候,程序就会崩溃,错误原因: reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]’。
看起来是数组訪问越界了,也就是说数组中仅仅有两个对象,可是却訪问了index为2的对象。于是程序就崩溃了。
检查了代码,并没有什么异常,最后想到是不是静态TableView导致的问题呢?
于是决定将TableView改动为动态的,并改动 WBDiscoverTableViewController.m中的代码:
#import "WBDiscoverTableViewController.h" @interface WBDiscoverTableViewController () @property ( weak , nonatomic ) IBOutlet UISearchBar *mySearchbar; @property ( nonatomic , strong ) NSArray *results; @end @implementation WBDiscoverTableViewController - ( void )viewDidLoad { [ super viewDidLoad ];
[ self . searchDisplayController . searchResultsTableView registerNib :[ UINib nibWithNibName : @"WBsearchSuggestionCell" bundle :[ NSBundle mainBundle ]] forCellReuseIdentifier : @"WBsearchSuggestionCell" ]; [ self . tableView registerNib :[ UINib nibWithNibName : @"hotTopicsCell1" bundle :[ NSBundle mainBundle ]] forCellReuseIdentifier : @"hotTopicsCell1" ]; [ self . tableView registerNib :[ UINib nibWithNibName : @"hotTopicsCell2" bundle :[ NSBundle mainBundle ]] forCellReuseIdentifier : @"hotTopicsCell2" ]; [ self . tableView registerNib :[ UINib nibWithNibName : @"nearbyPeopleCell" bundle :[ NSBundle mainBundle ]] forCellReuseIdentifier : @"nearbyPeopleCell" ]; [ self . tableView registerNib :[ UINib nibWithNibName : @"nearbyWeiboCell" bundle :[ NSBundle mainBundle ]] forCellReuseIdentifier : @"nearbyWeiboCell" ]; }
- ( void )searchWithString { switch ( self . mySearchbar . selectedScopeButtonIndex ) { case 0 : // 搜用户 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsUsersWithString : self . mySearchbar . text AndCount : 20 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; case 1 : // 搜学校 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsSchoolsWithString : self . mySearchbar . text AndCount : 20 AndType : 0 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; case 2 : // 搜公司 if ([[ NSUserDefaults standardUserDefaults ] objectForKey : @"accessToken" ]) { [[ WBWeiboAPI shareWeiboApi ] searchSuggestionsCompaniesWithString : self . mySearchbar . text AndCount : 20 CompletionCallBack :^( id obj) { self . results = obj; dispatch_async ( dispatch_get_main_queue (), ^{ NSLog ( @"self.results.count :%ld" , self . results . count ); [ self . searchDisplayController . searchResultsTableView reloadData ]; }); }]; } break ; default : break ; } }
#pragma mark UISearchBarDelegate
- ( void )searchBarSearchButtonClicked:( UISearchBar *)searchBar { [ self searchWithString ]; } #pragma mark UISearchDisplayDelegate - ( void )searchDisplayControllerWillBeginSearch:( UISearchDisplayController *)controller { NSLog ( @"WillBeginSearch...." ); } - ( void )searchDisplayControllerDidBeginSearch:( UISearchDisplayController *)controller { NSLog ( @"DidBeginSearch...." ); } - ( void )searchDisplayControllerWillEndSearch:( UISearchDisplayController *)controller { NSLog ( @"WillEndSearch...." ); } - ( void )searchDisplayControllerDidEndSearch:( UISearchDisplayController *)controller { NSLog ( @"DidEndSearch...." ); } - ( BOOL )searchDisplayController:( UISearchDisplayController *)controller shouldReloadTableForSearchString:( NSString *)searchString { [ self searchWithString ]; return NO ; } - ( BOOL )searchDisplayController:( UISearchDisplayController *)controller shouldReloadTableForSearchScope:( NSInteger )searchOption { [ self searchWithString ]; return NO ;
}
#pragma mark - Table view data source // 因为这个控制器既是原来的 WBDiscoverTableViewController ,又是 UISearchDisplayController 的 searchContentsController 。 //WBDiscoverTableViewController 的 tableView 和 searchResultsTableView 的 delegat 都指向这个对象( self )。 // 所以须要在回调中差别究竟是哪个 tableView - ( NSInteger )numberOfSectionsInTableView:( UITableView *)tableView { if (tableView == self . tableView ) { return 2 ; } else if (tableView == self . searchDisplayController . searchResultsTableView ){ return 1 ; } else return 0 ; } - ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section { if (tableView == self . tableView ) { return 2 ; } else if (tableView == self . searchDisplayController . searchResultsTableView ) { return self . results . count ; } else return 0 ; } - ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath { if (tableView == self . tableView ) { if (indexPath. section == 0 && indexPath. row == 0 ) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"hotTopicsCell1" forIndexPath :indexPath]; return cell; } else if (indexPath. section == 0 && indexPath. row == 1 ) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"hotTopicsCell2" forIndexPath :indexPath]; return cell; } else if (indexPath. section == 1 && indexPath. row == 0 ) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"nearbyPeopleCell" forIndexPath :indexPath]; return cell; } else { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier : @"nearbyWeiboCell" forIndexPath :indexPath]; return cell; } } else if (tableView == self . searchDisplayController . searchResultsTableView ) { WBsearchSuggestionCell *cell = [tableView dequeueReusableCellWithIdentifier : @"WBsearchSuggestionCell" forIndexPath :indexPath]; id result = self . results [indexPath. row ]; if ([result isMemberOfClass :[ WBSearchSuggestionsOfUsers class ]]) { WBSearchSuggestionsOfUsers * suggestion = result; cell. suggestion . text = suggestion. nickName ; } else if ([result isMemberOfClass :[ WBSearchSuggestionsOfSchools class ]]) { WBSearchSuggestionsOfSchools *suggestion = result; cell. suggestion . text = suggestion. schoolName ; } else { WBSearchSuggestionsOfCompanies *suggestion = result; cell. suggestion . text = suggestion. suggestion ; } return cell; } else return nil ; } - ( CGFloat )tableView:( UITableView *)tableView heightForHeaderInSection:( NSInteger )section { return 10 ; } - ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath :indexPath animated : YES ]; UIViewController *vc = [[ UIViewController alloc ] init ]; vc. view . backgroundColor = [ UIColor whiteColor ]; [ self . navigationController pushViewController :vc animated : YES ];
}
@end
測试,问题攻克了!
可是仍然心存疑问。为什么静态TableView会影响UISearchBar and Search Display Controller中 searchResultsTableView的cell?