近期学习过程中想模拟一下新浪微博“发现”界面。
我在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 {
@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 {
}
[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;
}
}
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];
}
[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;
}
- (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;
}
//因为这个控制器既是原来的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];
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];
@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"];
}
[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;
}
}
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;
[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?