NSFetchedResultsController OR谓词在iOS6上为某些项返回重复项



我正在使用NSFetchedResultsController将不同电子邮件帐户的消息加载到表视图和集合视图中。iOS7上的一切都很好,iOS6中的一切都很棒,除非我使用组合OR谓词。

现在我知道,如果NSFetchedResultsController与这些谓词中的多个匹配,它将两次返回同一项。我的问题是,消息实体只匹配这些谓词中的一个,但被返回的次数与谓词相同。

因此,出于某种原因,NSFetchedResultsController表示这些消息传递了所有谓词,但仅在iOS6上传递。它对来自特定电子邮件帐户的每一封邮件都这样做,但对来自其他帐户的邮件则不这样做。

如果我将OR谓词调整为不使用ObjectID,则会返回唯一的结果。然而,随着值的调整,我的UI将不再正确更新

就我而言,我似乎不知道这些实体究竟是如何传递其他电子邮件帐户和文件夹的谓词的。

导致重复的谓词构造如下。帐户->邮件是一对多的关系,文件夹<->消息太多了。

NSMutableArray *predicates = [NSMutableArray array];
for (CRMFolder *folder in comboFolder.folders) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isMarkedForDelete != YES AND isTopReferenceMessage = YES AND folders contains %@ AND account = %@", folder, folder.account];
[predicates addObject:predicate];
}
fetchRequest.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];

所以,如果我把它改成objectID,我会得到唯一的结果:

NSMutableArray *predicates = [NSMutableArray array];
for (CRMFolder *folder in comboFolder.folders) {
NSArray *objectIDs = [folder.messages valueForKey:@"objectID"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isMarkedForDelete != YES AND isTopReferenceMessage = YES AND self in %@", objectIDs];
[predicates addObject:predicate];
}
fetchRequest.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];

但如果我把这两者结合起来,我仍然会得到重复。

NSMutableArray *predicates = [NSMutableArray array];
for (CRMFolder *folder in comboFolder.folders) {
NSArray *objectIDs = [folder.messages valueForKey:@"objectID"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isMarkedForDelete != YES AND isTopReferenceMessage = YES AND folders contains %@ AND account = %@ AND self in %@", folder, folder.account, objectIDs];
[predicates addObject:predicate];
}
fetchRequest.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];

上的任何想法

1) 为什么这些实体传递它们不应该传递的谓词?

2) 为什么这只发生在iOS6上?

3) 解决办法是什么?

我知道我可以使用returnsDistinctResults,但这需要将所有内容转换为字典,而这目前还不是一个选项。

编辑

我刚刚做了一个测试,如果我排除了造成问题的帐户,结果是正常的。同样,我只是排除了所有其他账户,没有重复。因此,只有当这些谓词都结合在一起时,才会发生这种情况。我真的怀疑提取结果控制器中有什么错误。

编辑2

这是一个获取的原始CoreData日志,它会产生几个重复项。请注意,有3条消息重复了9次,得到了27个结果。

CoreData:注释:sql连接获取时间:0.0528s核心数据:sql:从Z_3BLINDCARBONCOPYMESSAGES t1选择t0.Z_PK,t1.Z_14BLINDCARBONCOMPYMESSES在t0.Z_PK=t1.Z_3BLindCARBONCIPIES中t1.Z_44BLINDCArbONCOMPYMAGES IN(276276276276276 276 276 276 276276286286624624624624)按t1.Z订购_14林德卡彭博社ASCCoreData:注释:sql执行时间:0.0004sCoreData:annotation:从联接表中预取数据库中的多对多关系"blindCarbonCopies"。已获得0行CoreData:sql:SELECT t0.Z_PK,t1.REFLEXIVE FROM Z_14REFERENCEMESSAGES t1 JOIN ZCRMMESSAGE t0 ON t0.Z_PK=t1.Z_14EFERENCEMESPAGES WHERE t1.REFERENTIVE IN(276276276276276 276276286286286624624624624)ORDER BY t1.REFELEXIVE ASCCoreData:注释:sql执行时间:0.0525sCoreData:annotation:从联接表中预取数据库中的多对多关系"referenceMessages"。已获得0行CoreData:sql:从Z_3CARBONCOPYMESSAGES t1选择t0.Z_PK,t1.Z_14CARBONCOPYMESSAGES t1加入ZCRMADDRESS t0 ON t0.Z_PK=t1.Z_3CARBONCOPIES其中t1.Z_1 4CarbonCOPymESSAGES IN(276276276276276 276276276286286286286624624624624)按t1.Z_ 14CARBONCOPYMESSAGES ASC订购CoreData:注释:sql执行时间:0.0270sCoreData:annotation:从联接表中预取数据库中的多对多关系"carbonCopies"。已获得0行CoreData:sql:SELECT t0.Z_PK,t1.Z_14ENDERMESSAGES FROM Z_3SENDERMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK=t1.Z_3SENDER其中t1.Z_24ENDERESSAGES INCoreData:注释:sql执行时间:0.0007sCoreData:annotation:从数据库中的多对多关系"发送方"的联接表中预取。有6排CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZIROFILEPHOTO,t0.ZFILEPHOTLASTCACHEDATE,t0.ZPROILEPHOTOSource,t0.CONTACT,t0.ZUSER FROM ZCRMADDRESS t0 WHERE t0.Z_PK IN(?,?)
CoreData:注释:sql连接提取时间:0.0004sCoreData:annotation:3行的总获取执行时间:0.0007s。CoreData:annotation:使用密钥"senders"预取。有三排。CoreData:sql:从ZCRMATTACHMENT t0选择0、t0.Z_PK、t0.Z_OPT、t0.ZCONTENTID、t0.ZDATA、t0.ZEXCHANGEID、t0.XFILEEXTENSION、t0.ZISLOCAL、t0.ZISTEMPORARY、t0.ZORIGINALFILENAME、t0.ZSIZEINBYTES、t0.ZTHUMBNAIL、t0.Z MESSAGE、t0.ZUSER其中t0.ZMESSAGE IN(CoreData:注释:sql连接获取时间:0.0005sCoreData:annotation:总获取执行时间:0行为0.0007s。CoreData:annotation:使用键"attachments"预取。得到0行。CoreData:sql:从Z_3REPLYTOMAGES t1选择t0.Z_PK,t1.Z_14REPLYTOMESSAGES t1加入ZCRMADDRESS t0 ON t0.Z_PK=t1.Z_3REPLY TOS其中t1.Z_1 4REPLYtomESSAGES IN(276276276276276 276276276286286286286624624624624)按t1.Z_CoreData:注释:sql执行时间:0.0006sCoreData:annotation:从联接表中预取数据库中的多对多关系"replyTos"。有6排CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZIROFILEPHOTO,t0.ZFILEPHOTLASTCACHEDATE,t0.ZPROILEPHOTOSource,t0.CONTACT,t0.ZUSER FROM ZCRMADDRESS t0 WHERE t0.Z_PK IN(?,?)
CoreData:注释:sql连接提取时间:0.0004sCoreData:annotation:3行的总获取执行时间:0.0006s。CoreData:annotation:使用键"replyTos"预取。有三排。CoreData:sql:从Z_3RECIPIENTMESSAGES t1选择t0.Z_PK,t1.Z_14RECIPIENTMESSAGES t0加入ZCRMADDRESS t0 ON t0.Z_PK=t1.Z_3 RECIPIENTS其中t1.Z_24RECIPEINTMESSAGESINCoreData:注释:sql执行时间:0.0006sCoreData:annotation:从联接表中为数据库中的多对多关系"收件人"预取。有6排CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZFROFILEPHOTO,t0.ZBROFILEPHOLASTCACHEDATE,t0.ZPROFILEPHOSource,t0.CONTACT,t0.ZUSER FROM ZCRMADDRESS t0 WHERE t0.Z_PK IN(?)
CoreData:注释:sql连接获取时间:0.0004sCoreData:annotation:总获取执行时间:1行0.0007s。CoreData:annotation:使用密钥"receives"预取。有1行。CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZENCRYPTEDBODY,t0.ZENCRYPTEDHTMLBODY,t0.ZENCRYPTEDPLAINTEXTBODY,t0.XENCRYPTEDSUBJECT,t0.ZCRMMESSAGEBODY t0 WHERE t0.ZMESSAGE IN(?,?,?提取时间:0.0011sCoreData:annotation:总获取执行时间:3行0.0015s。CoreData:annotation:使用键"messageBody"预取。有三排。CoreData:annotation:27行的总获取执行时间:0.1482秒。

正如Dan Shelly所指出的,CONTAINS在谓词中使用不正确。我相信,正如他所解释的,这只是为了在另一个字符串中找到一个子字符串。请参阅谓词文档。但是,出于您的目的,您可以使用子查询。

所以,我会跳到前面解决问题。您可以将您的副拨号更改为以下内容:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isMarkedForDelete != YES AND isTopReferenceMessage = YES AND SUBQUERY(folders, $folder, $folder = %@).@count != 0 AND account = %@", folder, folder.account];

正如Martin R.所指出的,一个获取请求不应该两次返回同一个元素。我不知道为什么会这样,如果它确实这样做了,除非它是使用无效谓词的结果。

此外,请注意,由于提取请求不应返回重复项,因此returnsDistinctResults的用法与听起来有点不同。你可以在这里找到一个例子。

最新更新