原创:知识点总结性文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容
目录
- 七、NSTimer
- 1、不重复的timer
- 2、重复的timer
- 3、Invocation + RunLoop
- 4、Fire Date + RunLoop
- 八、NSPredicate
- 1、谓词语法
- 2、正则表达式语法
- 3、包含关系
- 4、数据过滤
- 5、占位符
- 6、正则表达式
- 7、空值
- 8、复合谓词
- 9、Core Data中的使用
- Demo
- 参考文献
六、NSDate
1、Date
a、创建日期
// 使用时间间隔创建日期
NSTimeInterval secondsPerDay = 24 * 60 * 60;// 一天
NSDate *tomorrow1 = [[NSDate alloc] initWithTimeIntervalSinceNow:secondsPerDay];// 明天
NSDate *yesterday1 = [[NSDate alloc] initWithTimeIntervalSinceNow:-secondsPerDay];// 昨天
NSLog(@"使用时间间隔创建日期,昨天:%@,明天:%@",yesterday1, tomorrow1);
// 通过添加时间间隔创建日期
NSDate *today = [NSDate date];
NSDate *tomorrow2 = [today dateByAddingTimeInterval:secondsPerDay];// 明天
NSDate *yesterday2 = [today dateByAddingTimeInterval:-secondsPerDay];// 昨天
NSLog(@"通过添加时间间隔创建日期,昨天:%@,明天:%@",yesterday2, tomorrow2);
// 从1970年1月1日开始,20年之后的日期
NSDate *twentyYearsDate = [NSDate dateWithTimeIntervalSince1970:secondsPerDay*366*20];
NSLog(@"从1970年1月1日开始,20年之后的日期:%@",twentyYearsDate);
输出结果为:
2020-09-24 11:05:35.266263+0800 BasicGrammarDemo[97687:17759303] 使用时间间隔创建日期,昨天:2020-09-23 03:05:35 +0000,明天:2020-09-25 03:05:35 +0000
2020-09-24 11:05:35.266383+0800 BasicGrammarDemo[97687:17759303] 通过添加时间间隔创建日期,昨天:2020-09-23 03:05:35 +0000,明天:2020-09-25 03:05:35 +0000
2020-09-24 11:32:29.711559+0800 BasicGrammarDemo[98039:17779918] 从1970年1月1日开始,20年之后的日期:1990-01-16 00:00:00 +0000
b、比较日期
NSDate *today = [NSDate date];// 今天
NSDate *tomorrow = [today dateByAddingTimeInterval:24 * 60 * 60];// 明天
// 看看两个日期是否在一分钟(60秒)内
// fabs:求一个实数的绝对值
if (fabs([tomorrow timeIntervalSinceDate:today]) < 60)
{
NSLog(@"两个日期在一分钟(60秒)内");
}
else
{
NSLog(@"两个日期不在一分钟(60秒)内");
}
// 之前、相同、之后
switch ([today compare:tomorrow])
{
case NSOrderedAscending:
NSLog(@"之前");
break;
case NSOrderedSame:
NSLog(@"相等");
break;
case NSOrderedDescending:
NSLog(@"之后");
break;
}
// 返回比较的两个日期中更早的那个
today = [today earlierDate:tomorrow];
NSLog(@"较早的日期:%@",today);
// 返回比较的两个日期中更晚的那个
today = [today laterDate:tomorrow];
NSLog(@"较晚的日期:%@",today);
输出结果为:
2020-09-24 14:40:57.125611+0800 BasicGrammarDemo[99895:17885247] 两个日期不在一分钟(60秒)内
2020-09-24 14:40:57.125685+0800 BasicGrammarDemo[99895:17885247] 之前
2020-09-24 14:40:57.125769+0800 BasicGrammarDemo[99895:17885247] 较早的日期:2020-09-24 06:40:57 +0000
2020-09-24 14:40:57.125844+0800 BasicGrammarDemo[99895:17885247] 较晚的日期:2020-09-25 06:40:57 +0000
c、日期格式
// 时间的本地化
NSDate *today = [NSDate date];
NSLocale *locale = [NSLocale currentLocale];// 系统当前的Locale
[today descriptionWithLocale:locale];
NSLog(@"时间的本地化:%@",today);
// 创建两个NSLocale,分别代表中国、美国
NSLocale *locales[] = {[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"], [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]};
// 设置NSDateFormatter的日期、时间风格
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
// NSLocale
[dateFormatter setLocale:locales[0]];
// 设置自定义的格式模板
[dateFormatter setDateFormat:@"公元yyyy年MM月DD日 HH时mm分"];
// stringFromDate
NSString* stringFromDate = [dateFormatter stringFromDate:today];
NSLog(@"stringFromDate 时间的格式化:%@",stringFromDate);
// dateFromString
NSString *dateString = @"2020-01-18 06:50:24";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *dateFromString = [formatter dateFromString:dateString];
NSLog(@"dateFromString 时间的格式化:%@",dateFromString);
输出结果为:
2020-09-24 14:55:48.071631+0800 BasicGrammarDemo[309:17900007] 时间的本地化:2020-09-24 06:55:48 +0000
2020-09-24 14:55:48.072018+0800 BasicGrammarDemo[309:17900007] stringFromDate 时间的格式化:公元2020年09月268日 14时55分
2020-09-24 15:11:59.105726+0800 BasicGrammarDemo[764:17914033] dateFromString 时间的格式化:2020-01-17 22:50:24 +0000
d、时间戳
NSDate *today = [NSDate date];// 今天
NSDate *tomorrow = [today dateByAddingTimeInterval:24 * 60 * 60];// 明天
// 时间差
double interval = [today timeIntervalSinceDate:tomorrow];
NSLog(@"与明天的时间差:%f",interval);
// 与现在的时间差
interval = [today timeIntervalSinceNow];
NSLog(@"与现在的时间差:%f",interval);
输出结果为:
2020-09-24 14:40:57.126282+0800 BasicGrammarDemo[99895:17885247] 与明天的时间差:-86400.000000
2020-09-24 14:40:57.126339+0800 BasicGrammarDemo[99895:17885247] 与现在的时间差:-0.000070
2、Calendar
a、创建日历
// 创建日历对象
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
// local、usersCalendar和currentCalendar是相等的,尽管它们是不同的对象
NSCalendar *usersCalendar = [[NSLocale currentLocale] objectForKey:NSLocaleCalendar];
// 还可以通过为所需日历指定标识符来创建任意日历对象
// 获取代表公历的Calendar对象
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
b、通过日历获取不同时间字段的信息
NSDate *date = [NSDate date];
NSLog(@"现在日期为:%@",date);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday;
// 获取不同时间字段的信息
NSDateComponents *components = [gregorian components:unitFlags fromDate:date];
NSLog(@"年:%ld 月:%ld ",(long)components.year,(long)components.month);
输出结果为:
2020-09-24 11:17:01.315888+0800 BasicGrammarDemo[97860:17769221] 现在日期为:2020-09-24 03:17:01 +0000
2020-09-24 11:17:01.316009+0800 BasicGrammarDemo[97860:17769221] 年:2020 月:9
c、通过日历设置各时间字段的数值
// 设置各时间字段的数值
NSDateComponents *newComponents = [[NSDateComponents alloc] init];
newComponents.year = 2020;
newComponents.month = 10;
newComponents.day = 1;
// 恢复NSDate
date = [gregorian dateFromComponents:newComponents];
NSLog(@"设置的日期为:%@",date);
输出结果为:
2020-09-24 11:17:01.316112+0800 BasicGrammarDemo[97860:17769221] 设置的日期为:2020-10-17 16:00:00 +0000
d、日期组件
// 从日期获取组件
NSDate *today = [NSDate date];
// 获取代表公历的Calendar对象
NSCalendar *decompose = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// 指定将会获取指定周、日的信息
NSDateComponents *weekdayComponents = [decompose components:(NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:today];
NSInteger day = [weekdayComponents day];
NSInteger newWeekday = [weekdayComponents weekday];
NSLog(@"今天是:%@",today);
NSLog(@"从日期获取组件 day:%ld, newWeekday:%ld",(long)day,(long)newWeekday);
// 从组件创建日期
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:2];// 星期一
[components setWeekdayOrdinal:1];// 这个月的第一个星期一
[components setMonth:10];
[components setYear:2020];
NSDate *getDate = [decompose dateFromComponents:components];
NSLog(@"从组件创建日期:%@",getDate);
输出结果为:
2020-09-24 15:09:33.838392+0800 BasicGrammarDemo[724:17912053] 今天是:2020-09-24 07:09:33 +0000
2020-09-24 15:09:33.838503+0800 BasicGrammarDemo[724:17912053] 从日期获取组件 day:24, newWeekday:5
2020-09-24 15:09:33.838631+0800 BasicGrammarDemo[724:17912053] 从组件创建日期:2020-10-01 16:00:00 +0000
e、计算日期
NSDate *today = [[NSDate alloc] init];
NSDate *tomorrow = [[NSDate alloc] initWithTimeIntervalSinceNow:24 * 60 * 60];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
// 增加一个半小时后
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setHour:1];
[offsetComponents setMinute:30];
NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
NSLog(@"现在的时间是:%@",today);
NSLog(@"一个半小时后就是第三次世界大战的结束时间:%@",endOfWorldWar3);
// 通过减去日期来获取前一周的星期天 9月24日为周四,则上周日为9月20日,具有与原始日期相同的小时、分钟和秒
NSDateComponents *weekdayComponents = [gregorian components:NSCalendarUnitWeekday fromDate:today];
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
// 从当前日期减去的天数,公历中星期日的值是1,所以减去1,如果今天是星期日,则减去0天
[componentsToSubtract setDay:(0 - ([weekdayComponents weekday] - 1))];
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];
NSLog(@"通过减去日期来获取前一周的星期天:%@",beginningOfWeek);
// 获取两个日期之间的差异
NSUInteger unitFlags = NSCalendarUnitDay | NSCalendarUnitMonth;
NSDateComponents *components = [gregorian components:unitFlags fromDate:today toDate:tomorrow options:0];
NSInteger months = [components month];
// 输出两个日期day差数为0,因为8.5小时不到1天
NSInteger days = [components day];
NSLog(@"获取两个日期之间的差异,days:%ld,months:%ld",(long)days,(long)months);
输出结果为:
2020-09-24 15:27:18.050866+0800 BasicGrammarDemo[1024:17927076] 现在的时间是:2020-09-24 07:27:18 +0000
2020-09-24 15:27:18.050986+0800 BasicGrammarDemo[1024:17927076] 一个半小时后就是第三次世界大战的结束时间:2020-09-24 08:57:18 +0000
2020-09-24 15:27:18.051097+0800 BasicGrammarDemo[1024:17927076] 通过减去日期来获取前一周的星期天:2020-09-20 07:27:18 +0000
2020-09-24 15:27:18.051178+0800 BasicGrammarDemo[1024:17927076] 获取两个日期之间的差异,days:1,months:0
七、NSTimer
1、不重复的timer
// 在默认模式(NSDefaultRunLoopMode)下,用当前NSRunLoop对象自动注册新计时器
- (void)startTimer
{
// 计时器在2秒后由运行循环自动触发,然后从运行循环中删除
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(targetMethod:) userInfo:self.userInfo repeats:NO];
}
- (void)targetMethod:(NSTimer *)theTimer
{
NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"];
NSLog(@"开始日期:%@",startDate);
}
- (NSDictionary *)userInfo
{
return @{@"StartDate": [NSDate date]};
}
如果创建非重复计时器,它会自动停止。输出结果为:
2020-09-24 10:31:01.237970+0800 BasicGrammarDemo[97131:17724123] 开始日期:2020-09-24 02:30:59 +0000
2、重复的timer
- (void)startRepeatingTimer
{
// 取消之前存在的timer
[_repeatingTimer invalidate];
// 创建新的timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(targetMethod:) userInfo:self.userInfo repeats:YES];
_repeatingTimer = timer;
}
如果创建重复计时器,将计数器的repeats
设置为YES
的时候,self
的引用计数会加1,因此可能会导致self
(即viewController
)不能释放,所以必须在viewDidDisappear
方法里将计数器timer
停止,否则可能会导致内存泄露,停止后,一定要将timer
赋空,否则还是没有释放,会造成不必要的内存开销。
- (void)viewDidDisappear:(BOOL)animated
{
NSLog(@"退出了当前页面,销毁了定时器");
[self stopRepeatingTimer];
}
- (void)stopRepeatingTimer
{
// 将计数器timer停止,否则可能会导致内存泄露
[self.repeatingTimer invalidate];
// 停止后,一定要将timer赋空,否则还是没有释放,会造成不必要的内存开销
self.repeatingTimer = nil;
}
当再次进入定时器页面,重新开启定时器。
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"进入定时器页面,重新开启定时器");
// 开启定时器
[self.repeatingTimer setFireDate:[NSDate distantPast]];//很远的过去
}
输出结果为:
2020-09-24 10:39:10.396329+0800 BasicGrammarDemo[97268:17732297] 开始日期:2020-09-24 02:39:06 +0000
2020-09-24 10:39:10.896330+0800 BasicGrammarDemo[97268:17732297] 开始日期:2020-09-24 02:39:06 +0000
2020-09-24 10:39:11.243983+0800 BasicGrammarDemo[97268:17732297] 退出了当前页面,销毁了定时器
2020-09-24 10:39:13.011582+0800 BasicGrammarDemo[97268:17732297] 进入定时器页面,重新开启定时器
发现定时器被销毁了,无法重新开启,所以可以使用viewWillDisappear
替代viewDidDisappear
里的实现。
// 在页面消失的时候关闭定时器,然后等页面再次打开的时候,又开启定时器
- (void)viewWillDisappear:(BOOL)animated
{
// 关闭定时器
[self.repeatingTimer setFireDate:[NSDate distantFuture]]; //很远的将来
NSLog(@"退出了当前页面,只是关闭定时器未销毁,再次进入可重新启动");
}
输出结果为:
2020-09-24 10:41:46.070295+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000
2020-09-24 10:41:46.570290+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000
2020-09-24 10:41:46.879144+0800 BasicGrammarDemo[97329:17735552] 退出了当前页面,只是关闭定时器未销毁,再次进入可重新启动
2020-09-24 10:41:48.834727+0800 BasicGrammarDemo[97329:17735552] 进入定时器页面,重新开启定时器
2020-09-24 10:41:48.837701+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000
3、Invocation + RunLoop
- (void)createUnregisteredTimer
{
// 1、根据方法来初始化NSMethodSignature
// 方法签名中保存了方法的名称/参数/返回值,协同NSInvocation来进行消息的转发
NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(invocationMethod:)];
// 2、其实NSInvocation就是将一个方法变成一个对象
// NSInvocation中保存了方法所属的对象/方法名称/参数/返回值
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
// 设置方法调用者
[invocation setTarget:self];
// 设置方法名称,这里的方法名一定要与方法签名类中的方法一致
[invocation setSelector:@selector(invocationMethod:)];
NSDate *startDate = [NSDate date];
// 设置方法参数,这里的Index要从2开始,因为0跟1已经被占据了,分别是self(target),selector
[invocation setArgument:&startDate atIndex:2];
// 3、调用invoke方法
[invocation invoke];
// 使用invocation创建计时器
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 invocation:invocation repeats:YES];
self.unregisteredTimer = timer;
//[self addTimerToRunLoop];// 未添加到runloop中时
}
- (void)invocationMethod:(NSDate *)date
{
NSLog(@"调用日期为:%@", date);
}
输出结果显示尽管计时器被配置为重复,但在触发一次之后,即被停止。
2020-09-24 10:45:21.267890+0800 BasicGrammarDemo[97383:17739828] 调用日期为:2020-09-24 02:45:21 +0000
现在将timer
添加到run loop
中。当前线程是主线程时,某些UI事件,比如ScrollView
正在拖动,将会RunLoop
切换成 NSEventTrackingRunLoopMode
模式,添加到RunLoop
中的Timer
就不会执行。
为了设置一个不被UI干扰的Timer
,我们需要手动创建一个Timer
,然后使用RunLoop
的 addTimer:forMode:
方法来把Timer
按照指定的模式加入到RunLoop
中。这里使用 NSRunLoopCommonModes
模式,这个模式相当于 NSDefaultRunLoopMode
和 NSEventTrackingRunLoopMode
的结合。
// 将timer添加到run loop中
- (void)addTimerToRunLoop
{
if (self.unregisteredTimer != nil)
{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.unregisteredTimer forMode:NSDefaultRunLoopMode];
}
}
打开[self addTimerToRunLoop]
语句的注释,输出结果为:
2020-09-24 10:49:05.506717+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
2020-09-24 10:49:06.006756+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
2020-09-24 10:49:06.506797+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
.......
4、Fire Date + RunLoop
- (void)startFireDateTimer
{
// 用日期初始化计时器
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
// 尽管计时器被配置为重复,但在countedTimerFireMethod触发三次之后,它将停止
NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate interval:0.5 target:self selector:@selector(countedTimerFireMethod:) userInfo:self.userInfo repeats:YES];
self.timerCount = 1;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
}
// 给计时器计算调用次数
- (void)countedTimerFireMethod:(NSTimer *)theTimer
{
NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"];
NSLog(@"开始日期: %@,调用次数: %lu", startDate, (unsigned long)self.timerCount);
// 这将使计时器在触发三次后失效
self.timerCount++;
if (self.timerCount > 3)
{
[theTimer invalidate];
}
}
输出结果为:
2020-09-24 10:50:43.824386+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 1
2020-09-24 10:50:44.323420+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 2
2020-09-24 10:50:44.823579+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 3
八、NSPredicate
1、谓词语法
下面方法都是区分大小写的,如果要不区分大小写,则可以在运算符后面使用[c]
。
AND、&&:逻辑与
OR || 逻辑或
NOT ! 逻辑非
字符串比较运算符:
BEGINSWITH 检查某个字符串是否以指定的某个子串开头
ENDSWITH 检查某个字符串是否以指定的某个子串结尾
CONTAINS 检查某个字符串是否包含指定的某个子串
LIKE 检查某个字符串是否匹配指定的字符串模板
MATCHES 检查某个字符串是否匹配指定的正则表达式
操作集合的运算符:
ANY SOME 指定只要集合中任意一个元素满足条件,即可返回YES。
ALL 指定所有元素满足才返回YES。
NONE 指定没有任何元素满足条件才返回YES。
IN 只有当左边的表达式或值出现在右边的集合中才会返回YES。
数组:
array[index] 返回array数组中索引为index处的元素
array[FIRST] 返回array数组中第一个元素
array[LAST] 返回array数组中最后一个元素
array[SIZE] 返回array数组中元素的个数。
直接量:
FALSE NO 逻辑假
TRUE YES 逻辑真
NULL NIL 代表一个空值
SELF 代表正在被判断的对象
"text"或'text' 代表字符串
数组 数组元素用英文字符隔开。eg:{'keli','zhangsan','lisi','wangwu'}
数值直接量 包括整数、小数、科学计数法
2、正则表达式语法
^ 指出一个字符串的开始
$ 指出一个字符串的结束
"^iOS" 以iOS开头
"iOS$" 以iOS结尾
"^apple$" 开始和结尾都是apple的字符串,这个是唯一的,实际上就是apple
"apple" 包含apple
* + ? 重复出现的次数
? 0~1次
+ 1~n次
* 0~n次
"ab*" 一个a后面跟着0~n个b
"ab+" 一个a后面跟着至少一个b
"ab?" 一个a后面跟着0~1个b
"a?b+$" 末尾有0~1个a跟着1~n个b
{} 表示重复的具体范围
"ab{4}" 一个a跟着4个b
"ab{1,}" 一个a跟着至少1个b
"ab{3,5}" 一个a跟着3~5个b
* 可以用{0,}表示
+ 可以用{1,}表示
? 可以用{0,1}表示
| 或
"a|b" 一个字符串里有a或b
"(a|bcd)ef" aef或bcdef
"(a|b)+c" 一串a和b混合的字符串后面跟一个c;
[ ] 表示在括号内的众多字符中,选择1-n个括号内的符合语法的字符作为结果
"[ab]" 一个a或b(相当于"a|b");
"[a-d]" a到d中的一个(相当于"a|b|c|d"或者"[abcd]")
"^[a-zA-Z]" 以字母开头
"[0-9]a" a前有一位数字
"[a-zA-Z0-9]$"以一个字母或数字结束
. 任意字符
"a.[a-z]" a后面跟一个任意字符和一个小写字母
"^.{5}$" 长度为5的字符串
"@[^a-zA-Z]@" 在方括号里用^表示不希望出现的字符,^应在方括号里的第一位。表示两个@中不应该出现字母
"\d" 一个数字字符
"\D" 一个非数字字符
"\w " 包括下划线的任何单词字符
"\W" 匹配任何非单词字符
\ iOS中书写正则表达式,碰到转义字符,多加一个\
3、包含关系
IN
在集合中筛选出共同部分:
- (void)inArrayDemo
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@",@[@"先生女士",@"妙不可言",@"哈哈哈哈哈"]];
BOOL result = [predicate evaluateWithObject:@"哈哈哈哈哈"];
if (result)
{
NSLog(@"哈哈哈哈哈在数组中");
}
}
输出结果为:
2020-09-24 16:59:50.674351+0800 ChecksumsWarning[2412:18002210] 哈哈哈哈哈在数组中
筛选出set1
中与set2
中相同的元素:
NSSet<NSString *> *set1 = [NSSet setWithObjects:@"one", @"two", @"three", @"four", nil];
NSSet<NSString *> *set2 = [NSSet setWithObjects:@"three", @"four", @"five", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", set2];
NSSet<NSString *> *commonElements = [set1 filteredSetUsingPredicate:predicate];
NSLog(@"commonElements == %@", commonElements);
NOT
筛选出array1
与array2
不相同的元素:
NSSet<NSString *> *set1 = [NSSet setWithObjects:@"one", @"two", @"three", @"four", nil];
NSSet<NSString *> *set2 = [NSSet setWithObjects:@"three", @"four", @"five", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", set2];
NSSet<NSString *> *commonElements = [set1 filteredSetUsingPredicate:predicate];
NSLog(@"commonElements == %@", commonElements);
筛选出数组中不符合like
规则的元素:
NSArray <NSString *> *array = @[@"loading_001.png", @"loading_002.png", @"loading_003.png",@"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF LIKE %@)", @"loading_*.png"];
for (NSString * ele in array) {
NSLog(@"[%@]%@形如[loading_*.png]条件", ele, [predicate evaluateWithObject:ele] ? @"不符合" : @"符合");
}
CONTAINS
是否包含指定字串:
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@[China]", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
匹配字符串中是否包含指定的子串(忽略大小写)。如果需要忽略大小写可以使用[c]
来做筛选选项。
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[c] %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@[China]", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
LIKE
筛选具备某一类相似特征的字符串,通常使用*
作为通配符:
- (void)characterMatch
{
NSString *prefix = @"prefix";
NSString *suffix = @"suffix";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[c] %@",[[prefix stringByAppendingString:@"*"] stringByAppendingString:suffix]];
NSLog(@"predicate = %@", [predicate predicateFormat]);
BOOL result = [predicate evaluateWithObject:@"prefixxxxxxsuffix"];
if (result)
{
NSLog(@"字符匹配成功");
}
else
{
NSLog(@"字符匹配失败");
}
}
输出结果为:
2020-09-24 17:23:59.032000+0800 ChecksumsWarning[2770:18022215] predicate = SELF LIKE[c] "prefix*suffix"
2020-09-24 17:23:59.033539+0800 ChecksumsWarning[2770:18022215] 字符匹配成功
MATCH
匹配全是中文的字符串:
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"^[\\u4e00-\\u9fa5]+$"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@都是中文字符", ele, [predicate evaluateWithObject:ele] ? @"全部" : @"非全部");
}
匹配字符串中是否包含中文:
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @".*[\\u4e00-\\u9fa5]+.*"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@中文字符", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
4、数据过滤
a、比较大小
- (void)greaterThanDemo
{
NSArray* array = @[@101,@200,@50,@5,@25,@12];
NSLog(@"原数组:%@",array);
// 创建谓词,要求该对象自身的值大于50
NSPredicate *predicateThan50 = [NSPredicate predicateWithFormat:@"SELF > 50"];
// 使用谓词执行过滤,过滤后只剩下值大于50的集合元素
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicateThan50];
NSLog(@"数组过滤后只剩下值大于50的集合元素:%@",filteredArray);
}
输出结果为:
2020-09-24 16:18:24.591968+0800 ChecksumsWarning[1783:17966853] 原数组:(
101,
200,
50,
5,
25,
12
)
2020-09-24 16:18:24.592186+0800 ChecksumsWarning[1783:17966853] 数组过滤后只剩下值大于50的集合元素:(
101,
200
)
b、以特定字符开始和结尾
- (void)beginswithLetterDemo
{
// 过滤掉不是以b开始的字符串
NSMutableArray *letters = [@[@"Abc",@"Bbb",@"Ca"] mutableCopy];
NSPredicate *predictForArray = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB = [letters filteredArrayUsingPredicate:predictForArray];
NSLog(@"过滤掉不是以b开始的字符串:%@",beginWithB);
}
输出结果为:
2020-09-24 17:04:15.974855+0800 ChecksumsWarning[2479:18006076] 过滤掉不是以b开始的字符串:(
Bbb
)
筛选以China
结尾的字符串(不区分大小写):
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF ENDSWITH[c] %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]%@以%@结尾", ele, [predicate evaluateWithObject:ele] ? @"是" : @"不是", @"China");
}
c、逻辑运算符号
还可以使用诸如==, >, <, >=, <=,
以及AND, OR
等逻辑运算符号进行条件筛选。使用属性进行筛选时,可以省略SELF
直接使用属性名进行筛选,简化书写。例如筛选成绩小于60,大于90的同学时可以直接使用score < 60 OR score >90
。
筛选出name="Dong"
的同学:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name == %@ ", @"Dong"];
NSArray<Student *> *result = [students filteredArrayUsingPredicate:predicate];
NSLog(@"result == %@, name == %@", result, result.firstObject.name);
筛选出成绩大于80且小于90的同学:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"score >= 80 and score <= 90"];
NSArray<Student *> *result = [students filteredArrayUsingPredicate:predicate];
for (Student *stu in result) {
NSLog(@"name == %@, score == %lf", stu.name, stu.score);
}
需要注意的一点是,当属性名作为参数传入匹配范型的时候,不能使用%@
进行参数格式限定,而应该使用%K
进行格式限定。因为在默认的情况下,使用%@
时,系统会给参数添加引号例如:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@ ", @"Dong"];
编译之后会变成形如:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == 'Dong' "];
而不是:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"'name' == 'Dong' "];
所以当参数名需要使用参数进行传递时,需要使用:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@ ", @"name", @"Dong"];
而不是:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ == %@ ", @"name", @"Dong"];
5、占位符
a、占位符参数
- (void)placeholderDemo
{
NSString *name = @"name";
NSString *value = @"齐天大圣";
NSDictionary *ditc = @{@"name":@"我是齐天大圣孙悟空水帘洞花果山大王"};
// 创建谓词,该谓词中包含了2个占位符,相当于创建了谓词表达式 "name CONTAINS '齐天大圣'" 字典中的键为name的值是否包含"齐天大圣"
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K contains %@",name, value];
// 使用谓词执行判断
BOOL isContain = [predicate evaluateWithObject:ditc];
if (isContain)
{
NSLog(@"字典中的键为name的值包含齐天大圣");
}
else
{
NSLog(@"字典中的键为name的值不包含齐天大圣");
}
}
输出结果为:
2020-09-24 16:18:24.592350+0800 ChecksumsWarning[1783:17966853] 字典中的键为name的值包含齐天大圣
b、设置变量值
- (void)SUBSTRdemo
{
// $SUBSTR相当于一个变量,需要我们调用时为它设置值
NSPredicate* predicateTemplate = [NSPredicate predicateWithFormat:@"%K CONTAINS $SUBSTR" , @"number"];
// 使用NDDictionary指定SUBSTR的值为'50',这就相当于创建了谓词表达式"pass CONTAINS '50'"
NSPredicate* predicate = [predicateTemplate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:@"50",@"SUBSTR", nil]];
// 使用谓词执行判断
NSDictionary *ditc = @{@"number":@"50000123432425432"};
BOOL isContain = [predicate evaluateWithObject:ditc];
if (isContain)
{
NSLog(@"字典中的键为number的值包含50");
}
else
{
NSLog(@"字典中的键为number的值不包含50");
}
}
输出结果为:
2020-09-24 16:35:53.575536+0800 ChecksumsWarning[1992:17978505] 字典中的键为number的值包含50
6、正则表达式
- (void)regularExpressionsDemo
{
NSArray *array = @[@"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG",
@"CGGGATCCCTATCAAGGCACCTCTTCG", @"CATGCCATGGATACCAACGAGTCCGAAC",
@"CAT", @"CATCATCATGTCT", @"DOG"];
// 查找包含至少3个“CAT”序列重复的字符串,但后面没有“CA”
NSPredicate *catPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES '.*(CAT){3,}(?!CA).*'"];
NSArray *filteredArray = [array filteredArrayUsingPredicate:catPredicate];
NSLog(@"查找包含至少3个CAT序列重复的字符串,但后面没有CA:%@",filteredArray);
}
输出结果为:
2020-09-24 16:40:32.491094+0800 ChecksumsWarning[2084:17983367] 查找包含至少3个“CAT”序列重复的字符串,但后面没有“CA”:(
CATCATCATGTCT
)
7、空值
- (void)nullPredicateDemo
{
NSString *firstName = @"Xie";
NSArray *array = @[ @{ @"lastName" : @"JiaPei" }, @{ @"firstName" : @"Wang", @"lastName" : @"ErDe", @"birthday":[NSDate date]},@{ @"firstName" : @"Xie", @"lastName" : @"LingYun", @"birthday":[NSDate date]}];
// 姓为Xie或者为空
NSPredicate *predicateForNull = [NSPredicate predicateWithFormat:@"(firstName == %@) || (firstName = nil)", firstName];
// 使用谓词执行判断
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicateForNull];
NSLog(@"过滤后的数组为: %@", filteredArray);
BOOL ok = [predicateForNull evaluateWithObject: [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"firstName"]];
if (ok)
{
NSLog(@"存在姓为Xie或者为空");
}
else
{
NSLog(@"不存在姓为Xie或者为空");
}
}
输出结果为:
2020-09-24 16:51:12.268705+0800 ChecksumsWarning[2267:17993506] 过滤后的数组为: (
{
lastName = JiaPei;
},
{
birthday = "2020-09-24 08:51:12 +0000";
firstName = Xie;
lastName = LingYun;
}
)
2020-09-24 16:51:12.268825+0800 ChecksumsWarning[2267:17993506] 存在姓为Xie或者为空
8、复合谓词
- (void)compoundPredicateDemo
{
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"SELF > 10"];
NSLog(@"predicate1 = %@", [predicate1 predicateFormat]);
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"SELF < 50"];
NSLog(@"predicate2 = %@", [predicate2 predicateFormat]);
// NSAndPredicateType 多个谓词表达式之间添加AND,NSOrPredicateType 多个谓词表达式之间添加OR
NSCompoundPredicate *compound = [[NSCompoundPredicate alloc] initWithType:NSAndPredicateType subpredicates:@[predicate1, predicate2]];
NSLog(@"compound = %@", [compound predicateFormat]);
BOOL result = [compound evaluateWithObject:@20];
if (result)
{
NSLog(@"20在区间(20,50)内");
}
else
{
NSLog(@"20不在区间(20,50)内");
}
}
输出结果为:
2020-09-24 17:17:16.746394+0800 ChecksumsWarning[2669:18016834] predicate1 = SELF > 10
2020-09-24 17:17:16.746510+0800 ChecksumsWarning[2669:18016834] predicate2 = SELF < 50
2020-09-24 17:17:16.746617+0800 ChecksumsWarning[2669:18016834] compound = SELF > 10 AND SELF < 50
2020-09-24 17:17:16.746715+0800 ChecksumsWarning[2669:18016834] 20在区间(20,50)内
9、Core Data中的使用
- (void)coreDataPredicate
{
NSManagedObjectContext *managedObjectContext;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSInteger salaryLimit = 100;
// 查找收入超过指定金额的员工
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"salary > %@", salaryLimit];
[request setPredicate:predicate];
// 查询结果
NSError *error;
NSArray *resultArray = [managedObjectContext executeFetchRequest:request error:&error];
}
Demo
Demo在我的Github上,欢迎下载。
BasicsDemo