iOS个人整理21-UISearchController搜索框与NSPredicate谓词

一、UISearchController


搜索框的用处很大,就不用废话了,在iOS8以前是用UISearchBar加代理实现的。

现在已经废弃,鼓励使用新的UISearchController

首先遵守UISearchResultsUpdating

@interface RootTableViewController ()<UISearchResultsUpdating>

再实现必须的方法-(void)updateSearchResultsForSearchController:(UISearchController *)searchController

//搜索代理方法,搜索框获得第一响应或内容变化时触发
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
   NSLog(@激活了搜索框");
}

再创建UISearchController,因为很多方法都要对搜索框进行判断,写成一个属性

@property (nonatomic,retain)UISearchController *searchC;

初始化UISearchController,把搜索框添加在tableView的headerView上

    //添加搜索栏
    _searchC = [[UISearchController alloc]initWithSearchResultsController:nil];
    //设置frame
    _searchC.searchBar.frame = CGRectMake(0, 0, 414, 50);
    
    //更新代理
    _searchC.searchResultsUpdater = self;
    
    //搜索结果不变灰
    _searchC.dimsBackgroundDuringPresentation = NO;
    
    //添加到header
    self.tableView.tableHeaderView = _searchC.searchBar;

这样运行就能看到搜索框了,点击也会打印文字。


二、NSPredicate谓词

光有搜索框没什么卵用,还要有搜索功能,内部的功能就需要谓词来实现了

谓词的功能很强大,同时它还可以使用正则表达式,可以实现各种邮箱验证,手机号验证,以及各种查找功能。

使用的方法

1.创建谓词

NSPredicate *testPredicate = [NSPredicate predicateWithFormat:@"age < 50"];

谓词的语法也很全面:

Format后面可以跟很多:

(1)比较运算符>,<,==,>=,<=,!=
可用于数值及字符串
例:@"number > 100"


(2)范围运算符:IN、BETWEEN
例:@"number BETWEEN {1,5}"
      @"address IN {'shanghai','beijing'}"


(3)字符串本身:SELF 
例:@“SELF == ‘APPLE’"


(4)字符串相关:BEGINSWITH、ENDSWITH、CONTAINS
例:@"name CONTAIN[cd] 'ang'"   //包含某个字符串
       @"name BEGINSWITH[c] 'sh'"     //以某个字符串开头
       @"name ENDSWITH[d] 'ang'"      //以某个字符串结束
        注:[c]不区分大小写[d]不区分发音符号即没有重音符号[cd]既不区分大小写,也不区分发音符号。


(5)通配符:LIKE
例:@"name LIKE[cd] '*er*'"    //*代表通配符,Like也接受[cd].
       @"name LIKE[cd] '???er*'"


(6)正则表达式:MATCHES
例:NSString *regex = @"^A.+e$";   //以A开头,e结尾
      @"name MATCHES %@",regex

用正则表达式简单匹配一个邮箱

 正则表达式常用的
    /*
     ^ ---  匹配输入字符串的开始位置
    $ ---  匹配输入字符串的结束位置
    * --- 匹配前面的子表达式任意次
     + --- 匹配前面的子表达式一次或多次
     ? --- 匹配前面的子表达式零次或一次
     .点 --- 匹配除“\r\n”之外的任何单个字符
     \d --- 匹配一个数字字符。等价于[0-9]
    \D --- 匹配一个非数字字符。等价于[^0-9]。
     \w --- 等价于[A-Za-z_0-9]。
     \转义
     
     */

    //匹配一个邮箱地址
    //结构 (字母数字)@(字母数字)(.)(字母2~4个)
    NSString *emailRegex = @"\\w+@\\w+\\.[A-Za-z]{2,4}";

    NSPredicate *emailPredicate = [NSPredicate predicateWithFormat:@"name MATCHES %@",emailRegex];




2.进行过滤,有两种方法,

一种是对数组进行过滤,把符合谓词条件的对象产生一个新的数组

一种是单独判断一个对象是否满足谓词条件,返回值为BOOL

 //过滤产生新的数组
    self.searchArray =  [NSMutableArray arrayWithArray:[_dataArray filteredArrayUsingPredicate:testPredicate]];
    
//对单个对象依次判断
  if ([testPredicate evaluateWithObject:personDic]) 
  {
         //添加到搜索数组当中去
         [_searchArray addObject:personDic];
   }

这里要注意一点,数组内放的对象可以是一个字典,也可以是一个类。




最后给出我写的完整的tableView上搜索框的使用


//
//  RootTableViewController.m


#import "RootTableViewController.h"
#import "Person.h"

@interface RootTableViewController ()<UISearchResultsUpdating>

@property (nonatomic,retain)NSMutableArray *dataArray;//全部数据数组
@property (nonatomic,retain)NSMutableArray *searchArray;//搜索结果数组

@property (nonatomic,retain)UISearchController *searchC;//搜索框

@end

@implementation RootTableViewController
//懒加载
-(NSMutableArray *)dataArray
{
    if (!_dataArray) {
        _dataArray = [[NSMutableArray alloc]init];
    }
    return _dataArray;
}
-(NSMutableArray *)searchArray
{
    if (!_searchArray) {
        _searchArray = [[NSMutableArray alloc]init];
    }
    return _searchArray;
}


- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationItem.title = @"search";
    
    //添加搜索栏
    _searchC = [[UISearchController alloc]initWithSearchResultsController:nil];
    
    _searchC.searchBar.frame = CGRectMake(0, 0, 414, 50);
    
    //更新代理
    _searchC.searchResultsUpdater = self;
    
    //搜索结果不变灰
    _searchC.dimsBackgroundDuringPresentation = NO;
    
    //便利初始化创建数据

    NSArray *nameArray = [NSArray arrayWithObjects:@"王",@"李型剂",@"王青云",@"张菲菲",@"abe",@"ABe",@"aBS",@"wang@12.com", @"wan@126.cn",nil];

    int ageList[] = {12,43,56,123,34,44,21,22,11};
    for (int i = 0; i < 9; i++) {
        Person *person = [Person personWithName:nameArray[i] Age:(NSInteger)ageList[i]];
        
        //把全部人存到数组当中去
        [self.dataArray addObject:person];
    }
    
    //添加到header
    self.tableView.tableHeaderView = _searchC.searchBar;
    
    //注册单元格
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CELL"];
    
}

//搜索代理方法,搜索框获得第一响应或内容变化时触发
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    //得到搜索框的文字
    NSString* str = searchController.searchBar.text;
    NSLog(@"%@",str);
    //创建个谓词
    // < > >= <= !=
    NSPredicate *testPredicate = [NSPredicate predicateWithFormat:@"age < 50"];
    
    //IN BETWEEN
    NSPredicate *testPredicate_2 = [NSPredicate predicateWithFormat:@"age BETWEEN {50,100}"];
    NSPredicate *testPredicate_3 = [NSPredicate predicateWithFormat:@"name IN{'王','张菲菲'}"];
    
    //testPredicate
//    @"name CONTAINS[cd] 'ang'"   //包含某个字符串
//    @"name BEGINSWITH[c] 'sh'"     //以某个字符串开头
//    @"name ENDSWITH[d] 'ang'"      //以某个字符串结束
    NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@"name CONTAINS %@",str];
    
    //[c]不区分大小写 [d]无音调  [cd]两个都不要
     NSPredicate *namePredicate_2 = [NSPredicate predicateWithFormat:@"name CONTAINS[c] %@ ",str];
   
    //正则表达式    
    //匹配一个邮箱地址
    //结构 (字母数字)@(字母数字)(.)(字母2~4个)
    NSString *emailRegex = @"\\w+@\\w+\\.[A-Za-z]{2,4}";

    NSPredicate *emailPredicate = [NSPredicate predicateWithFormat:@"name MATCHES %@",emailRegex];
    
    //清空搜索数组
    [_searchArray removeAllObjects];
    
    //过滤,这里可以换不同的谓词进行试验
    self.searchArray =  [NSMutableArray arrayWithArray:[_dataArray filteredArrayUsingPredicate:namePredicate_2]];
    
    for (Person *person in _searchArray) {
        NSLog(@"%@,%ld",person.name,person.age);
    }
    
    //刷新tableView
    [self.tableView reloadData];

}


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Incomplete implementation, return the number of sections
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete implementation, return the number of rows
    
    //如果搜索框激活
    if (_searchC.active) {
        return _searchArray.count;
    }
    return _dataArray.count;
}

//cell的填充
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL" forIndexPath:indexPath];
    
    Person *onePerson = _dataArray[indexPath.row];
    
    //如果搜索框激活
    if (_searchC.active) {
        onePerson = _searchArray[indexPath.row];
    }
    
    cell.textLabel.text = [NSString stringWithFormat:@"姓名:    %@, ----- 年龄:    %ld",onePerson.name,onePerson.age];
    
    return cell;
}

@end

person类

Person.h

//
//  Person.h
//  TestPredicate

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,retain)NSString *name;//姓名
@property (nonatomic,assign)NSInteger age;//年龄

//init
-(instancetype)initWithName:(NSString*)name Age:(NSInteger)age;

//便利
+(instancetype)personWithName:(NSString*)name Age:(NSInteger)age;

@end

Person.m

//
//  Person.m
//  TestPredicate
//

#import "Person.h"

@implementation Person
//重写初始化方法
-(instancetype)initWithName:(NSString *)name Age:(NSInteger)age
{
    self = [super init];
    if (self) {
        _age = age;
        _name = name;
    }
    return self;
}

//便利构造器
 +(instancetype)personWithName:(NSString *)name Age:(NSInteger)age
{
    Person *person = [[Person alloc]initWithName:name Age:age];
    return person;
}

@end

效果如下

         


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用NSPredicate的Swift代码示例,用于将大量数据按时间分组: ```swift struct DataItem { let name: String let timeStamp: TimeInterval // 时间戳 } func groupDataByTime(_ data: [DataItem]) -> [[DataItem]] { // 将数据按时间先后排序 let sortedData = data.sorted { $0.timeStamp < $1.timeStamp } // 创建空字典 var groups = [String: [DataItem]]() // 使用NSPredicate过滤并分组数据 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" for item in sortedData { let date = Date(timeIntervalSince1970: item.timeStamp) let dateString = dateFormatter.string(from: date) let predicate = NSPredicate(format: "SELF.dateString == %@", dateString) let filteredArray = (groups as NSDictionary).filtered(using: predicate) if var items = filteredArray.first?.value as? [DataItem] { items.append(item) groups[dateString] = items } else { groups[dateString] = [item] } } // 将分组后的数据按时间先后顺序排序 let sortedGroups = groups.sorted { $0.key < $1.key } // 将所有分组添加到一个数组中 var result = [[DataItem]]() for (_, items) in sortedGroups { result.append(items) } return result } ``` 在这个示例中,我们同样定义了一个`DataItem`结构体来表示数据的名称和时间戳。`groupDataByTime`函数首先将数据按时间先后排序,然后使用`NSPredicate`过滤并分组数据。我们指定`NSPredicate`的格式为`SELF.dateString == %@`,其中`dateString`是我们根据时间戳计算得到的时间字符串,`%@`是用于替换的占位符。通过对字典进行过滤,我们可以得到一个包含指定时间字符串的数组,然后将新的数据项添加到这个数组中。最后,我们将所有分组添加到一个大数组中,按时间先后顺序排序,并返回结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值