进一步澄清“如何用objective c实现UISearchController”

Posted

技术标签:

【中文标题】进一步澄清“如何用objective c实现UISearchController”【英文标题】:Further clarification of "How to implement UISearchController with objective c" 【发布时间】:2015-11-25 00:04:59 【问题描述】:

我一直在尝试通过关注***线程来实现UISearchController

How to implement UISearchController with objective c

和 Apples 的文档,但无法使其正常工作。当初始控制器(EVTSearchViewController 定义为UIViewController)符合UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating, UITableViewDelegate (我也需要使其与UITableViewDelegate 兼容,因为我使它成为其他UITableViewController 类型EVTSearchResultsViewController *resultsControllers tableView 的代表)代表出现了,我看到我的.xib 带有UISearchBar 和@ 987654336@,我点击搜索栏开始输入:

当我输入一个字母时,搜索栏消失并且什么也没有显示:

首先,我不希望搜索栏消失。其次,updateSearchResultsForSearchController 似乎根本没有被调用,因为NSLog() 在那里设置在我在搜索栏中输入时不会产生任何输出。

我有.xib 用于EVTSearchViewController,它有一个UISearchBar,我正在连接到相应的属性:IBOutlet UISearchBar *searchBar,然后指向 UISearchControllers 的搜索栏:

self.searchBar = self.searchController.searchBar

还有UITableView,我在.xib 中放在UISearchBar 下方。我在EVTSearchViewController 中使用的另一个控制器是EVTSearchResultsViewController,它是UITableViewController,它没有.xib

下面是viewDidLoadupdateSearchResultsForSearchController 方法的代码:

- (void)viewDidLoad

_resultsController = [[EVTSearchResultsViewController alloc] init];
_searchController = [[UISearchController alloc] initWithSearchResultsController:_resultsController];

self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
self.searchBar = self.searchController.searchBar;


// we want to be the delegate for our filtered table so didSelectRowAtIndexPath is called for both tables
self.resultsController.tableView.delegate = self;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = YES; // default is YES
self.searchController.searchBar.delegate = self; // so we can monitor text changes + others

// Search is now just presenting a view controller. As such, normal view controller
// presentation semantics apply. Namely that presentation will walk up the view controller
// hierarchy until it finds the root view controller or one that defines a presentation context.
//
self.definesPresentationContext = YES;  // know where you want UISearchController to be displayed


- (void)updateSearchResultsForSearchController:(UISearchController *)searchController 

// update the filtered array based on the search text
NSString *searchText = searchController.searchBar.text;
NSLog(@"searchText: %@", searchText);
if (searchText == nil) 

    // If empty the search results are the same as the original data
    self.searchResults = [[[EVTItemStore sharedStore] allItems] mutableCopy];

 else 

    NSMutableArray *searchResults = [[NSMutableArray alloc] init];

    NSArray *allEvents = [[EVTItemStore sharedStore] allItems];
    NSLog(@"allEvents: %@", allEvents);
    for (EVTItem *event in allEvents) 

        /*if ([event.number containsString:searchText] || [[phoneMO.closrr_id filteredId] containsString:searchText] || [[phoneMO.contact.fullname lowercaseString] containsString:[searchText lowercaseString]]) 
            [searchResults addObject:phoneMO];
        */
        if ([event.eventName containsString:searchText]) 
            [searchResults addObject:event];
        
    

    self.searchResults = searchResults;



// hand over the filtered results to our search results table
EVTSearchResultsViewController *resultsController = (EVTSearchResultsViewController *)self.searchController.searchResultsController;
resultsController.filteredEvents = self.searchResults;
[resultsController.tableView reloadData];

EVTSearchViewController中定义的各个@properties

@interface EVTSearchViewController ()
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;

@property (nonatomic, strong) UISearchController *searchController;
@property (nonatomic, strong) EVTSearchResultsViewController *resultsController;
@property (nonatomic, strong) NSMutableArray *searchResults;

// For state restoration
@property BOOL searchControllerWasActive;
@property BOOL searchControllerSearchFieldWasFirstResponder;

@end

那么,这里是EVTSearchResultsViewController的代码:

#import "EVTSearchResultsViewController.h"

@implementation EVTSearchResultsViewController

- (instancetype)init

// Call the superclass's designated initializer
self = [super initWithStyle:UITableViewStylePlain];

if (self) 

return self;


- (void)viewDidLoad 
[super viewDidLoad];

[self.tableView registerClass:[UITableViewCell class]
       forCellReuseIdentifier:@"UISearchViewCell"];



- (void)didReceiveMemoryWarning 
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.


- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section 

return [self.filteredEvents count];


- (UITableViewCell *)tableView:(UITableView *)tableView
     cellForRowAtIndexPath:(NSIndexPath *)indexPath 
UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:@"UISearchViewCell"
                                forIndexPath:indexPath];

cell.textLabel.text = self.filteredEvents[indexPath.row];

return cell;


@end

上面EVTSearchResultsViewController的方法根本没有被调用,这让我看起来很奇怪,那我们为什么需要它呢?

我尝试按照 Apple 文档推荐的方式设置 UISearchBar

self.resultsTableView.tableHeaderView = self.searchController.searchBar;

但它给了我一个无响应的搜索框,所以当按下时没有任何反应。

有人可以帮忙解决这个问题吗?上面链接的另一个问题也可以澄清。谢谢。

【问题讨论】:

您的实现似乎过于复杂。您通常希望将 uisearchbar 添加到要搜索的 tableview 中,而不是分布在多个类和 xib 中。尝试从一个非常简单的示例从头开始,直到您了解编码模式。 好吧,我相信所有的事情都是必需的,应该以这种方式(或类似方式)完成,再简单不过了。如果你看一下苹果文档,它已经很复杂了:developer.apple.com/library/ios/documentation/UIKit/Reference/… 现在调用这些方法,所以我更好地了解工作流程。我现在有两个主要问题:当一个视图覆盖另一个视图时,图像在上面表示的一个问题;另一个是updateSearchResultsForSearchController中的NSString *searchText = searchController.searchBar.text在我输入文本时没有设置。 我现在遇到的主要问题是上面显示的问题,当一个视图运行在另一个视图之上时。我解决了设置文本的问题(我只看到正确的 NSLog() 输出) 您应该使用文档中的这一行:self.tableView.tableHeaderView = self.searchController.searchBar;正如我在第一条评论中建议的那样,请参阅您发送给我的链接以获取更多详细信息。 【参考方案1】:

所以,我解决了这个问题并使用UISearchController 实现了基本搜索。下面是我们实现基本搜索需要做的事情:

    创建两个没有.xib 文件的UITableViewControllers 类。是的,应该没有.xib 文件,我们只是创建了两个类。在下面的代码中,他们的名字是EVTSearchViewControllerEVTSearchResultsViewController。 使控制器之一符合委托:<UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>

这里是EVTSearchViewController的头文件代码:

#import <UIKit/UIKit.h>

@interface EVTSearchViewController : UITableViewController <UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>

@end

这是EVTSearchResultsViewController的标题:

#import <UIKit/UIKit.h>

@interface EVTSearchResultsViewController : UITableViewController

@property (nonatomic, strong) NSMutableArray *filteredEvents;

@end

NSMutableArray *filteredEvents 将保存搜索结果。我们不应该在EVTSearchViewController.m 中实现任何UITableViewController 委托方法,而应该在EVTSearchResultsViewController.m 中实现。

这是EVTSearchViewController的上半部分:

#import "EVTSearchViewController.h"
#import "EVTSearchResultsViewController.h"

// Importing the class that stores `EVTItem` object classes
#import "EVTItemStore.h"
#import "EVTItem.h"

@interface EVTSearchViewController ()
@property (nonatomic, strong) UISearchController *searchController;
// We created this class
@property (nonatomic, strong) EVTSearchResultsViewController *resultsController;
// array to hold the results of the search
@property (nonatomic, strong) NSMutableArray *searchResults;

@end

这是EVTSearchViewControllerviewDidLoad:方法的代码:

- (void)viewDidLoad

[super viewDidLoad];
self.resultsController = [[EVTSearchResultsViewController alloc] init];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsController];

self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.placeholder = nil;
[self.searchController.searchBar sizeToFit];
// This line of code is very important. Here we are using apple docs'
// suggestion. UITableViewController has tableView property, so
// we are just setting tableView`s header to apples' UISearchController`s' `searchBar property
self.tableView.tableHeaderView = self.searchController.searchBar;

self.searchController.delegate = self;

// default is YES
self.searchController.dimsBackgroundDuringPresentation = YES;

// so we can monitor text changes + other changes
self.searchController.searchBar.delegate = self;

// know where you want UISearchController to be displayed
self.definesPresentationContext = YES;

然后我们给EVTSearchViewController添加如下方法:

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController 

// update filtered array based on the search text
NSString *searchText = searchController.searchBar.text;
if (searchText == nil) 

    // If empty the search results should be the same as the original data
    self.searchResults = [[[EVTItemStore sharedStore] allItems] mutableCopy];

 else 

    NSMutableArray *searchResults = [[NSMutableArray alloc] init];

// [[EVTItemStore sharedStore] allItems] message retrieves
// all of the objects that I have in datastore EVTItemStore
    NSArray *allEvents = [[EVTItemStore sharedStore] allItems];

// EVTItem class has a property eventName which we are using
// for searching, then adding it to our searchResults array
    for (EVTItem *event in allEvents) 
        if ([event.eventName containsString:searchText]) 
            [searchResults addObject:event];
        
    

    self.searchResults = searchResults;


// hand over the filtered results to our search results table
EVTSearchResultsViewController *resultsController = (EVTSearchResultsViewController *)self.searchController.searchResultsController;
resultsController.filteredEvents = self.searchResults;
[resultsController.tableView reloadData];

另一个控制器的EVTSearchResultsViewController@implementation 部分如下所示:

@implementation EVTSearchResultsViewController

- (instancetype)init

// Call the superclass's designated initializer
self = [super initWithStyle:UITableViewStylePlain];

if (self) 

return self;


- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section 
return [self.filteredEvents count];



- (UITableViewCell *)tableView:(UITableView *)tableView
     cellForRowAtIndexPath:(NSIndexPath *)indexPath 

UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:@"UISearchViewCell"
                                forIndexPath:indexPath];
EVTItem *event = self.filteredEvents[indexPath.row];
cell.textLabel.text = event.eventName;
return cell;


- (void)viewDidLoad

[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class]
                         forCellReuseIdentifier:@"UISearchViewCell"];


@end

就是这样。如果我们需要进一步自定义我们的单元格,我们应该能够通过将UISearchViewCell.xib 设置为EVTSearchResultsViewController 并使用以下viewDidLoad 来代替:

- (void)viewDidLoad

[super viewDidLoad];

// Load the NIB file
UINib *nib = [UINib nibWithNibName:@"UISearchViewCell" bundle:nil];

// Register this NIB which contains the cell
[self.tableView registerNib:nib forCellReuseIdentifier:@"UISearchViewCell"];

【讨论】:

非常感谢您的一切。 :)

以上是关于进一步澄清“如何用objective c实现UISearchController”的主要内容,如果未能解决你的问题,请参考以下文章

Redis作者:近期核心功能的一些思考和澄清

解决问题第一步:澄清问题之5WHY法寻找根本原因

Git中的合并是对称的吗?

下一步是啥();在这段代码中?

PHP强制函数调用

有效需求分析--引导篇