一:实现需求
根据 类别(小学,初中,高中),级别,性质,区域等条件来筛选云图中的数据,使其显示的地图上;当前地图可视范围内最多显示30条数据(10个学校名称,20个麻点),边移动或者缩放要边重新获取数据并且筛选数据。
二:实现难点和解决方案
1:高德筛选的接口筛选一个字段只能连续筛选且多条件筛选传参数也极其不方便;
@property (nonatomic, strong) NSArray *filter;
示例:数组{@"type:酒店", @"star:[3,5]"}的含义,等同于SQL语句:WHERE type = "酒店" AND star BETWEEN 3 AND 5
2:所以只能客户端获取当前可视地图区域数据后再进行筛选
1):一次请求只能获取100条数据,不能一次把当前数据筛选完;
/// 可选, 每页记录数(每页最大记录数100, 默认20)
@property (nonatomic, assign) NSInteger offset;
/// 可选, 当前页数(>=1, 默认1)
@property (nonatomic, assign) NSInteger page;
解决方案:
上一页有100条,并且没筛选到30条就再获取下一页数据;
筛选出来30条,或者云图筛选完毕就去地图展示数据;
2):先从云图获取数据再进行最多四种条件的筛选
以前的做法:
NSMutableArray *foods = [@[] mutableCopy];for(Food *foodinself.sources) {if([food.nameisEqualToString:@"呵呵"]) {
[arrayMaddObject:food];
}
}
//做一个筛选 - 筛选完或者筛选了30个结果后显示出来
//四筛一
//四筛二
//四筛三
//四筛四
这种做法在要筛选四种条件的情况下将会非常低效,而且复杂,情况非常多;
现在的做法:
NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。
可以使用谓词来表示逻辑条件,用于描述对象持久性存储在内存中的对象过滤。其实意思就是:我是一个过滤器,不符合条件的都滚开。
NSPredicate的基本语法
我们使用一门语言,无论是外语还是计算机语言,总是从语法开始的,这样我们才能正确的把握逻辑。所以我们从语法开始说起。在这部分我们仅关心其语法的使用
只要我们使用谓词(NSPredicate)都需要为谓词定义谓词表达式,而这个表达式必须是一个返回BOOL的值。
谓词表达式由表达式、运算符和值构成。
-(void)filterFourConditonWihtPois:(NSArray *)pois{
[self.predicateArr removeAllObjects];
if (self.typeArr.count) {
//address customFields
NSPredicate * p1 = [NSPredicate predicateWithFormat:@"type in %@", self.typeArr];//SELF
[self.predicateArr addObject:p1];
}
if (self.gradeArr.count) {
NSPredicate * p2 = [NSPredicate predicateWithFormat:@"grade in %@", self.gradeArr];
[self.predicateArr addObject:p2];
}
if (self.is_publicArr.count) {
NSPredicate * p3 = [NSPredicate predicateWithFormat:@"is_public in %@", self.is_publicArr];
[self.predicateArr addObject:p3];
}
if (self.disArr.count) {
NSPredicate * p4 = [NSPredicate predicateWithFormat:@"dis_id in %@", self.disArr];
[self.predicateArr addObject:p4];
}
if (self.predicateArr.count) {
// NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicateArr];
NSPredicate * predicate = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicateArr];
NSInteger count = 0;
for (AMapCloudPOI *aPOI in pois) {
BOOL match = [predicate evaluateWithObject:aPOI.customFields];
NSLog (@"%s", (match) ? "YES" : "NO");//看到这里我们会发现evaluateWithObject:方法返回的是一个BOOL值,如果符合条件就返回YES,不符合就返回NO。
if (match) {
[self.selectedPoiArray addObject:aPOI];
count ++;
if (count == 30) {
break;
}
}
}
//上一页有100条,并且没筛选到30条就再获取下一页数据
if (self.dataCount == 100 && count < 30) {
self.page ++;
[self cloudPlacePolygonSearch];
}else{//筛选出来30条,或者云图筛选完毕就去地图展示数据
if (count == 0) {
[self.view makeToast:@"未筛选到数据"];
}
[self addAnnotionsWithPOIs:self.selectedPoiArray];
}
}else{
[self addAnnotionsWithPOIs:pois];
}
}
注意事项:
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"is_public in %@", self.is_publicArr];
筛选语句里面的数字不能为字符串类型,要转换成数字类型,否则不能筛选成功;
for (NSString * str in arr[0]) {
if ([str isEqualToString:@"公办"]) {
NSNumber * number =[NSNumber numberWithInt:1];
[self.is_publicArr addObject:number];
}else if ([str isEqualToString:@"私立"]){
NSNumber * number =[NSNumber numberWithInt:0];
[self.is_publicArr addObject:number];
}
}