You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法为NSPredicateEditor设置带NOT运算符的单个子谓词

解决NSPredicateEditor显示“None”行搭配单个子行的问题

问题原因

NSPredicateEditor的NSNotPredicateType复合行模板默认要求子谓词必须是AND/OR类型的复合谓词,而非单个基础比较谓词。直接用NOT包裹单个简单谓词时,编辑器无法匹配到对应的模板结构,因此抛出异常。

解决方案

方法一:将单个子谓词包装为复合谓词(简单直接)

把需要的单个基础谓词用AND或OR复合谓词包裹后再套上NOT,就能匹配现有模板结构:

// 方式1:用NSCompoundPredicate构建
NSPredicate *singleSubPredicate = [NSPredicate predicateWithFormat:@"sampleName CONTAINS ''"];
// 用AND包裹单个子谓词(OR也可)
NSCompoundPredicate *compoundSubPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[singleSubPredicate]];
editor.objectValue = [NSCompoundPredicate notPredicateWithSubpredicate:compoundSubPredicate];

// 方式2:直接用谓词格式字符串(括号包裹单个谓词,隐式创建复合结构)
editor.objectValue = [NSPredicate predicateWithFormat:@"NOT (sampleName CONTAINS '')"];

这种方式会渲染出“None”(对应NOT)行,下方嵌套一个“All”(对应AND)行,再往下是单个基础条件行,能实现你需要的“None + 单个子行”逻辑。

方法二:自定义支持NOT直接包裹简单谓词的行模板(精准匹配)

如果不想多出中间的AND/OR层,可自定义行模板,让NOT模板直接支持单个基础谓词作为子项:

@interface NotWithSinglePredicateRowTemplate : NSPredicateEditorRowTemplate
@property (nonatomic, strong) NSPredicateEditorRowTemplate *baseTemplate;
@end

@implementation NotWithSinglePredicateRowTemplate

- (instancetype)initWithBaseTemplate:(NSPredicateEditorRowTemplate *)baseTemplate {
    self = [super init];
    if (self) {
        _baseTemplate = baseTemplate;
    }
    return self;
}

// 匹配NOT包裹单个简单谓词的结构
- (BOOL)matchesPredicate:(NSPredicate *)predicate {
    if (![predicate isKindOfClass:[NSCompoundPredicate class]]) return NO;
    NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate;
    if (compound.compoundPredicateType != NSNotPredicateType) return NO;
    if (compound.subpredicates.count != 1) return NO;
    NSPredicate *subPredicate = compound.subpredicates.firstObject;
    return [self.baseTemplate matchesPredicate:subPredicate];
}

// 生成对应的NOT谓词
- (NSPredicate *)predicateWithSubpredicates:(NSArray<NSPredicate *> *)subpredicates {
    if (subpredicates.count != 1) return nil;
    return [NSCompoundPredicate notPredicateWithSubpredicate:subpredicates.firstObject];
}

// 指定子模板数量
- (NSInteger)numberOfSubpredicates {
    return 1;
}

// 返回对应的基础子模板
- (NSPredicateEditorRowTemplate *)templateForSubpredicateAtIndex:(NSInteger)index {
    if (index == 0) return self.baseTemplate;
    return nil;
}

@end

修改模板初始化代码,替换原有的复合模板:

// 创建基础模板
NSMutableArray *finalTemplates = [NSMutableArray arrayWithCapacity:2];
for(NSString *keyPath in @[@"sampleName",@"comment"]) {
    NSPredicateEditorRowTemplate *template = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions:@[[NSExpression expressionForKeyPath:keyPath]]
                                                                                     rightExpressionAttributeType:NSStringAttributeType
                                                                                                         modifier:NSDirectPredicateModifier
                                                                                                        operators:@[@(NSContainsPredicateOperatorType), @(NSBeginsWithPredicateOperatorType)]
                                                                                                          options: 0];
    [finalTemplates addObject:template];
}

// 创建自定义NOT+单个基础模板
NSMutableArray *customCompoundTemplates = [NSMutableArray array];
for (NSPredicateEditorRowTemplate *baseTemplate in finalTemplates) {
    NotWithSinglePredicateRowTemplate *notTemplate = [[NotWithSinglePredicateRowTemplate alloc] initWithBaseTemplate:baseTemplate];
    [customCompoundTemplates addObject:notTemplate];
}

// 添加原有的AND/OR复合模板
NSArray *compoundTypes = @[@(NSAndPredicateType), @(NSOrPredicateType)];
NSPredicateEditorRowTemplate *compound = [[NSPredicateEditorRowTemplate alloc] initWithCompoundTypes:compoundTypes];
[customCompoundTemplates addObject:compound];

// 设置编辑器模板
editor.rowTemplates = customCompoundTemplates;

现在直接使用NOT sampleName CONTAINS ''这类谓词,编辑器会直接渲染“None”行搭配单个基础子行,无多余中间层。

补充说明

你之前测试的NOT (sampleName CONTAINS '' OR comment CONTAINS '')能正常工作,是因为括号内的OR是复合谓词,符合默认NOT模板对“子谓词为复合类型”的要求,因此编辑器能匹配到对应模板结构。

内容的提问来源于stack exchange,提问作者jeanlain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 02:09:09