* github:https://github.com/SunriseOYR/SKUDataFilter
* bigo:https://www.jianshu.com/p/295737e2ac77
#import
#import
@class ORSKUDataFilter;
@class ORSKUProperty;
@protocolORSKUDataFilterDataSource
@required
//属性种类个数
- (NSInteger)numberOfSectionsForPropertiesInFilter:(ORSKUDataFilter*)filter;
/*
* 每个种类所有的的属性值
* 这里不关心具体的值,可以是属性ID, 属性名,字典、model
*/
- (NSArray*)filter:(ORSKUDataFilter*)filter propertiesInSection:(NSInteger)section;
//满足条件 的 个数
- (NSInteger)numberOfConditionsInFilter:(ORSKUDataFilter*)filter;
/*
* 对应的条件式
* 这里条件式的属性值,需要和propertiesInSection里面的数据类型保持一致
*/
- (NSArray*)filter:(ORSKUDataFilter*)filter conditionForRow:(NSInteger)row;
//条件式 对应的 结果数据(库存、价格等)
- (id)filter:(ORSKUDataFilter*)filter resultOfConditionForRow:(NSInteger)row;
@end
@interfaceORSKUDataFilter :NSObject
@property (nonatomic, assign) id
//当前 选中的属性indexPath
@property(nonatomic,strong,readonly)NSArray *selectedIndexPaths;
//当前 可选的属性indexPath
@property(nonatomic,strong,readonly)NSSet *availableIndexPathsSet;
//当前 结果
@property (nonatomic, strong, readonly) id currentResult;
//init
- (instancetype)initWithDataSource:(id)dataSource;
//选中 属性的时候 调用
- (void)didSelectedPropertyWithIndexPath:(NSIndexPath*)indexPath;
//重新加载数据
- (void)reloadData;
@end
@interfaceORSKUCondition :NSObject
@property (nonatomic, strong) NSArray
@property (nonatomic, strong, readonly) NSArray
@property (nonatomic, strong) id result;
@end
@interfaceORSKUProperty :NSObject
@property (nonatomic, copy, readonly) NSIndexPath * indexPath;
@property (nonatomic, copy, readonly) id value;
- (instancetype)initWithValue:(id)value indexPath:(NSIndexPath*)indexPath;
@end
#import "ORSKUDataFilter.h"
@interface ORSKUDataFilter()
@property (nonatomic, strong) NSSet
@property(nonatomic,strong)NSMutableArray *selectedIndexPaths;
@property(nonatomic,strong)NSMutableSet *availableIndexPathsSet;
//全可用的
@property(nonatomic,strong)NSSet *allAvailableIndexPaths;
@property (nonatomic, strong) id currentResult;
@end
@implementationORSKUDataFilter
- (instancetype)initWithDataSource:(id)dataSource
{
self= [superinit];
if(self) {
_dataSource= dataSource;
_selectedIndexPaths = [NSMutableArray array];
[self initPropertiesSkuListData];
}
return self;
}
- (instancetype)init
{
self= [superinit];
if(self) {
_selectedIndexPaths = [NSMutableArray array];
}
return self;
}
- (void)reloadData {
[_selectedIndexPaths removeAllObjects];
[self initPropertiesSkuListData];
[self updateCurrentResult];
}
#pragma mark -- public method
//选中某个属性
- (void)didSelectedPropertyWithIndexPath:(NSIndexPath*)indexPath {
if (![_availableIndexPathsSet containsObject:indexPath]) {
//不可选
return;
}
if(indexPath.section> [_dataSourcenumberOfSectionsForPropertiesInFilter:self] || indexPath.item>= [[_dataSourcefilter:selfpropertiesInSection:indexPath.section]count]) {
//越界
NSLog(@"indexPath is out of range");
return;
}
if([_selectedIndexPathscontainsObject:indexPath]) {
//已被选
[_selectedIndexPathsremoveObject:indexPath];
[self updateAvailableIndexPaths];
[self updateCurrentResult];
return;
}
__blockNSIndexPath*lastIndexPath =nil;
[_selectedIndexPathsenumerateObjectsUsingBlock:^(NSIndexPath*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
if(indexPath.section== obj.section) {
lastIndexPath = obj;
}
}];
if(!lastIndexPath) {
//添加新属性
[_selectedIndexPathsaddObject:indexPath];
[_availableIndexPathsSet intersectSet:[self availableIndexPathsFromSelctedIndexPath:indexPath sectedIndexPaths:_selectedIndexPaths]];
[self updateCurrentResult];
return;
}
if(lastIndexPath.item!= indexPath.item) {
//切换属性
[_selectedIndexPathsaddObject:indexPath];
[_selectedIndexPathsremoveObject:lastIndexPath];
[self updateAvailableIndexPaths];
[self updateCurrentResult];
}
}
#pragma mark -- private method
//获取初始数据
- (void)initPropertiesSkuListData {
NSMutableSet *modelSet = [NSMutableSet set];
for(inti =0; i < [_dataSourcenumberOfConditionsInFilter:self]; i ++) {
ORSKUCondition *model = [ORSKUCondition new];
NSArray* conditions = [_dataSourcefilter:selfconditionForRow:i];
if(![selfcheckConformToSkuConditions:conditions]) {
NSLog(@"第 %d 个 condition 不完整 \n %@", i, conditions);
continue;
}
model.properties= [selfpropertiesWithConditionRawData:conditions];
model.result = [_dataSource filter:self resultOfConditionForRow:i];
[modelSetaddObject:model];
}
_conditions= [modelSetcopy];
[self getAllAvailableIndexPaths];
}
//检查数据是否正确
- (BOOL)checkConformToSkuConditions:(NSArray*)conditions {
if (conditions.count != [_dataSource numberOfSectionsForPropertiesInFilter:self]) {
returnNO;
}
__blockBOOL flag =YES;
[conditionsenumerateObjectsUsingBlock:^(id _Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
NSArray*properties = [_dataSourcefilter:selfpropertiesInSection:idx];
if(![propertiescontainsObject:obj]) {
flag =NO;
*stop =YES;
}
}];
returnflag;
}
//获取属性
- (NSArray *)propertiesWithConditionRawData:(NSArray*)data {
NSMutableArray *array = [NSMutableArray array];
[dataenumerateObjectsUsingBlock:^(id _Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
[arrayaddObject:[selfpropertyOfValue:objinSection:idx]];
}];
returnarray;
}
- (ORSKUProperty*)propertyOfValue:(id)value inSection:(NSInteger)section {
NSArray*properties = [_dataSourcefilter:selfpropertiesInSection:section];
NSString *str = [NSString stringWithFormat:@"Properties for %ld dosen‘t exist %@", (long)section, value];
NSAssert([properties containsObject:value], str);
NSIndexPath*indexPath = [NSIndexPathindexPathForItem:[propertiesindexOfObject:value]inSection:section];
return[[ORSKUPropertyalloc]initWithValue:valueindexPath:indexPath];
}
//获取条件式 对应 的数据
- (id)skuResultWithConditionIndexs:(NSArray *)conditionIndexs {
__blockidresult =nil;
[_conditionsenumerateObjectsUsingBlock:^(ORSKUCondition*_Nonnullobj,BOOL*_Nonnullstop) {
if([obj.conditionIndexsisEqual:conditionIndexs]) {
result = obj.result;
*stop =YES;
}
}];
returnresult;
}
//获取初始可选的所有IndexPath
- (NSMutableSet *)getAllAvailableIndexPaths {
NSMutableSet *set = [NSMutableSet set];
[_conditionsenumerateObjectsUsingBlock:^(ORSKUCondition*_Nonnullobj,BOOL*_Nonnullstop) {
[obj.conditionIndexsenumerateObjectsUsingBlock:^(NSNumber*_Nonnullobj1,NSUIntegeridx1,BOOL*_Nonnullstop1) {
[setaddObject:[NSIndexPathindexPathForItem:obj1.integerValueinSection:idx1]];
}];
}];
_availableIndexPathsSet = set;
_allAvailableIndexPaths = [set copy];
returnset;
}
//选中某个属性时 根据已选中的系列属性 获取可选的IndexPath
- (NSMutableSet *)availableIndexPathsFromSelctedIndexPath:(NSIndexPath*)selectedIndexPath sectedIndexPaths:(NSArray *)indexPaths{
NSMutableSet *set = [NSMutableSet set];
[_conditionsenumerateObjectsUsingBlock:^(ORSKUCondition*_Nonnullobj,BOOL*_Nonnullstop) {
if([obj.conditionIndexsobjectAtIndex:selectedIndexPath.section].integerValue== selectedIndexPath.item) {
[obj.propertiesenumerateObjectsUsingBlock:^(ORSKUProperty*_Nonnullproperty,NSUIntegeridx2,BOOL*_Nonnullstop1) {
//从condition中添加种类不同的属性时,需要根据已选中的属性过滤
//过滤方式为 condition要么包含已选中 要么和已选中属性是同级
if(property.indexPath.section!= selectedIndexPath.section) {
__blockBOOLflag =YES;
[indexPathsenumerateObjectsUsingBlock:^(NSIndexPath*_Nonnullobj1,NSUIntegeridx,BOOL*_Nonnullstop) {
flag = (([obj.conditionIndexs[obj1.section]integerValue] == obj1.row) || (obj1.section== property.indexPath.section)) && flag;
}];
if(flag) {
[setaddObject:property.indexPath];
}
}else{
[setaddObject:property.indexPath];
}
}];
}
}];
//合并本行数据
[_allAvailableIndexPathsenumerateObjectsUsingBlock:^(NSIndexPath*_Nonnullobj,BOOL*_Nonnullstop) {
if(obj.section== selectedIndexPath.section) {
[setaddObject:obj];
}
}];
returnset;
}
//当前可用的
- (void)updateAvailableIndexPaths {
if (_selectedIndexPaths.count == 0) {
_availableIndexPathsSet = [_allAvailableIndexPaths mutableCopy];
return;
}
__block NSMutableSet *set = [NSMutableSet set];
NSMutableArray *seleted = [NSMutableArray array];
[_selectedIndexPathsenumerateObjectsUsingBlock:^(NSIndexPath*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
[seletedaddObject:obj];
NSMutableSet*tempSet =nil;
tempSet = [self availableIndexPathsFromSelctedIndexPath:obj sectedIndexPaths:seleted];
if(set.count==0) {
set = [tempSetmutableCopy];
}else{
[setintersectSet:tempSet];
}
}];
_availableIndexPathsSet = set;
}
// 当前结果
- (void)updateCurrentResult {
if (_selectedIndexPaths.count != [_dataSource numberOfSectionsForPropertiesInFilter:self]) {
_currentResult = nil;
return;
}
NSMutableArray *conditions = [NSMutableArray array];
for (int i = 0; i < [_dataSource numberOfSectionsForPropertiesInFilter:self]; i ++) {
[_selectedIndexPathsenumerateObjectsUsingBlock:^(NSIndexPath*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
if(obj.section== i) {
[conditionsaddObject:@(obj.row)];
}
}];
}
_currentResult = [self skuResultWithConditionIndexs:[conditions copy]];
}
- (BOOL)isAvailableWithPropertyIndexPath:(NSIndexPath*)indexPath {
__blockBOOLisAvailable =NO;
[_conditionsenumerateObjectsUsingBlock:^(ORSKUCondition*_Nonnullobj,BOOL*_Nonnullstop) {
if([obj.conditionIndexsobjectAtIndex:indexPath.section].integerValue== indexPath.row) {
isAvailable =YES;
*stop =YES;
}
}];;
returnisAvailable;
}
#pragma mark -- setter
- (void)setDataSource:(id)dataSource {
_dataSource= dataSource;
[self initPropertiesSkuListData];
}
@end
@implementation ORSKUCondition
- (void)setProperties:(NSArray *)properties {
_properties= properties;
NSMutableArray *array = [NSMutableArray array];
[propertiesenumerateObjectsUsingBlock:^(ORSKUProperty*_Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
[arrayaddObject:@(obj.indexPath.item)];
}];
_conditionIndexs = [array copy];
}
@end
@implementation ORSKUProperty
- (instancetype)initWithValue:(id)value indexPath:(NSIndexPath*)indexPath
{
self= [superinit];
if(self) {
_value= value;
_indexPath= indexPath;
}
return self;
}
@end