NSPredicate比较密钥,其中一个可能是零

时间:2013-07-17 12:14:28

标签: iphone ios core-data nspredicate nsmanagedobject

我有一个NSManagedObject子类Foo,它有两个建模属性:ab

abNSString s,但无法保证它们会被实例化 - 它们也可能是nil。事实上,正如现在所发生的那样,所有Foo个实例都b等于nil

我想获取所有Fooa != b

对象
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Foo"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"a != b"];    
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:nil];

结果数组是空的,即使我知道事实的情况我有10个对象a肯定 {{ 1}}。

事实上,我甚至可以通过调整我的谓词来证明:

nil

哪个工作正常,并将10个对象返回给我。

fetchRequest.predicate = [NSPredicate predicateWithFormat:@"a != nil"]; / NSPredicate的这种行为很简单,我无法弄清楚为什么它会为NSFetchRequest谓词返回一个空结果,其中a != bb null。但是当我将其更改为a != nil(这只是b的硬编码值时)工作正常!!)

编写了一些测试代码来探讨这个问题,似乎在比较密钥时,如果==属性的LHS或RHS是nil,那么结果数组是空的。 / p>

另一方面,如果LHS和RHS都是非nil,那么它似乎工作正常。

我在这里缺少什么?为什么==运算符在比较其中一个或两个都是nil的两个键时会失败?

1 个答案:

答案 0 :(得分:2)

nil值在SQLite数据库中存储为NULL,SQLite将NULL视为 “未定义的价值”。谓词“a!= b”被转换为SQLite查询

SELECT ... FROM ZENTITY t0 WHERE  t0.ZA <> t0.ZB

并且不返回t0.ZAt0.ZB为NULL(又名“未定义”)的任何行。 因此,a != b不会返回abnil的任何对象。

出于同样的原因,谓词a == b不返回a的对象 bnil

另一方面,谓词a != nil

的转换略有不同
SELECT ... FROM ZENTITY t0 WHERE   t0.ZA IS NOT NULL

使用“IS NOT”代替“&lt;&gt;”。因此,此查询确实返回所有对象 a != nil(正如人们所料)。

我不知道Core Data文档中是否明确记录了此行为 (我还没有搜索过),但这就是SQLite如何处理NULL值,它应该解释 你观察到的行为。

如果添加启动参数

,则可以看到SQLite语句
-com.apple.CoreData.SQLDebug 3

表示Scheme编辑器中的可执行文件。

更新:来自“核心数据编程指南”中的"Attributes"

  

您可以指定属性是可选的 - 也就是说,不是   需要有价值。但是,一般来说,你是沮丧的   从这样做 - 特别是对于数值(通常你可以得到   使用带有默认值的强制属性的更好结果   模型 - 0)。原因是SQL有特殊的比较   与Objective-C的nil不同的NULL行为。数据库中为NULL   与0不同,搜索0与列不匹配   NULL。

这至少提到可选属性是特殊的,可能不是 表现得像预期的那样。

"Predicate Programming Guide"还有一个关于NULL值和测试NULL的部分。