ios 对UISearchController的封装使所有的回
在之前的一片文章UISearchController中介绍了
UISearchController
的使用,可以看到其中涉及到很多的委托,在使用UISearchController
的时候需要导入相关的协议,设置代理,然后实现协议中的方法。每次都这样写还是比较麻烦的。所以可以对UISearchController
做一次封装。将遵循协议、设置代理、实现方法这套流程放在UISearchController
的子类中来实现,子类对外暴露一组Block
属性。这样代理方法的要实现的功能就可以通过Block
来完成啦。
YBSearchController.h文件
#import <UIKit/UIKit.h>
@interface YBSearchController : UISearchController
/**
设置是否一直显示搜索结果页面
*/
@property (nonatomic) BOOL alwaysShowResultsViewController;
/**
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^updateSearchResultsForSearchController)(UISearchController *searchController);
/**
- (void)willPresentSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^willPresentSearchController)(UISearchController *searchController);
/**
- (void)didPresentSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^didPresentSearchController)(UISearchController *searchController);
/**
- (void)willDismissSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^willDismissSearchController)(UISearchController *searchController);
/**
- (void)didDismissSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^didDismissSearchController)(UISearchController *searchController);
/**
- (void)presentSearchController:(UISearchController *)searchController
*/
@property (nonatomic,copy) void(^presentSearchController)(UISearchController *searchController);
/**
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
*/
@property (nonatomic,copy) void(^searchBarSearchButtonClicked)(UISearchBar *searchBar);
/**
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
*/
@property (nonatomic,copy) void(^searchBarCancelButtonClicked)(UISearchBar *searchBar);
@end
YBSearchController.m文件
#import "YBSearchController.h"
@interface YBSearchController ()<UISearchControllerDelegate,UISearchResultsUpdating,UISearchBarDelegate>
@end
@implementation YBSearchController
- (void)dealloc
{
@try
{
// 此处可能多次删除KVO导致崩溃,目前没有找到更好的解决办法所以使用@try @catch 语句块防止程序崩溃
if (self.alwaysShowResultsViewController && self.searchResultsController) {
[self.searchResultsController.view removeObserver:self forKeyPath:@"hidden"];
}
}
@catch (NSException *e) {
NSLog(@"删除KVO报错");
NSLog(@"%@",e);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.delegate = self;
self.searchBar.delegate = self;
self.searchResultsUpdater = self;
if (self.alwaysShowResultsViewController && self.searchResultsController) {
[self.searchResultsController.view addObserver:self forKeyPath:@"hidden" options:0 context:NULL];
}
}
// 监听 self.searchController.searchResultsController.view 的hidden属性,让搜索结果页面一直显示
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ( object == self.searchResultsController.view && [keyPath isEqualToString:@"hidden"] && self.searchResultsController.view.hidden && self.searchBar.isFirstResponder )
{
self.searchResultsController.view.hidden = NO;
}
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
self.updateSearchResultsForSearchController ? self.updateSearchResultsForSearchController(self) : nil;
}
- (void)willPresentSearchController:(UISearchController *)searchController
{
self.willPresentSearchController ? self.willPresentSearchController(self) : nil;
}
- (void)didPresentSearchController:(UISearchController *)searchController
{
self.didPresentSearchController ? self.didPresentSearchController(self) : nil;
}
- (void)willDismissSearchController:(UISearchController *)searchController
{
self.willDismissSearchController ? self.willDismissSearchController(self) : nil;
}
- (void)didDismissSearchController:(UISearchController *)searchController
{
self.didDismissSearchController ? self.didDismissSearchController(self) : nil;
}
- (void)presentSearchController:(UISearchController *)searchController
{
self.presentSearchController ? self.presentSearchController(self) : nil;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
self.searchBarSearchButtonClicked ? self.searchBarSearchButtonClicked(self.searchBar) : nil;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
self.searchBarCancelButtonClicked ? self.searchBarCancelButtonClicked(searchBar) : nil;
}
@end
注意点
-
YBSearchController
是UISearchController
的子类。所以使用方法与UISearchController
的使用方法一样,只是在需要使用UISearchController的代理方法的时候改成了我们封装的Block属性来实现。 -
在上面的YBSearchController.m方法中我们可以看到为了让搜索结果页面
searchResultsController
一直显示我们使用到了KVO技术。来监听searchResultsController.view
的hidden
属性并在监听的回调方法observeValueForKeyPath: ofObject: change: context:
中设置self.searchResultsController.view.hidden = NO
。这个地方有一点需要注意那就是:“在使用KVO的时候可能会造成死循环”。因为我们监听的是self.searchResultsController.view
的hidden
属性变化,那么当我们在监听的回调方法中改变这个hidden
属性又会被监听到然后再调一次回调方法.........。这样就造成了循环调用。为了解决这个问题我们需要在改变hidden
属性值的地方加上一个判断如下面的代码。当hidden
等于true
的时候就不在改变hidden
的属性啦
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (self.searchResultsController.view.hidden && object == self.searchResultsController.view && [keyPath isEqualToString:@"hidden"] && self.searchBar.isFirstResponder )
{
self.searchResultsController.view.hidden = NO;
}
}