我正在使用NSFetchedResultsController将不同电子邮件帐户的邮件加载到tableview和集合视图中。在iOS7上一切都很好用,当我使用组合的OR谓词时,除了iOS6外,一切都很好用。
现在我知道NSFetchedResultsController如果匹配多个这些谓词,将返回相同的项两次。我的问题是,消息实体只与这些预测中的一个匹配但是与谓词返回的次数相同。
因此,由于某种原因,NSFetchedResultsController说这些消息传递所有谓词,但仅在iOS6上传递。它是针对来自特定电子邮件帐户的每封邮件执行此操作,但不会针对来自其他帐户的邮件执行此操作。
如果我将OR谓词调整为取消ObjectIDs,则返回唯一结果。但是,随着值的调整,我的UI将无法再正确更新
对于我的生活,我似乎无法弄清楚这些实体究竟是如何传递其他电子邮件帐户和文件夹的谓词。
导致重复的我的谓词结构如下。帐户 - >消息是oneToMany关系,文件夹< - >消息是manyToMany。
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];
因此,如果我将其更改为objectIDs,我会获得独特的结果:
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
CoreData:sql:SELECT t0.Z_PK,t1.Z_14BLINDCARBONCOPYMESSAGES FROM Z_3BLINDCARBONCOPYMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK = t1.Z_3BLINDCARBONCOPIES where t1.Z_14BLINDCARBONCOPYMESSAGES IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,624,614,624,624,624)按顺序排列t1.Z_14BLINDCARBONCOPYMESSAGES ASC
CoreData:注释:sql执行时间:0.0004s
CoreData:注释:从连接表中预取多对多关系" blindCarbonCopies"来自数据库。得了0行
CoreData:sql:SELECT t0.Z_PK,t1.REFLEXIVE FROM Z_14REFERENCEMESSAGES t1 JOIN ZCRMMESSAGE t0 ON t0.Z_PK = t1.Z_14REFERENCEMESSAGES where t1.RELEXLEX IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,612)顺序自适应ASC
CoreData:注释:sql执行时间:0.0525s
CoreData:注释:从连接表中预取多对多关系" referenceMessages"来自数据库。得了0行
CoreData:sql:SELECT t0.Z_PK,t1.Z_14CARBONCOPYMESSAGES FROM Z_3CARBONCOPYMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK = t1.Z_3CARBONCOPIES where t1.Z_14CARBONCOPYMESSAGES IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,641 t1.Z_14碳氢化合物ASC的顺序
CoreData:注释:sql执行时间:0.0270s
CoreData:注释:从连接表中预取多对多关系" carbonCopies"来自数据库。得了0行
CoreData:sql:SELECT t0.Z_PK,t1.Z_14SENDERMESSAGES FROM Z_3SENDERMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK = t1.Z_3SENDERS WHERE t1.Z_14SENDERMESSAGES IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,624,624,624,624)按t1.Z_14SENDERMESSAGES ASC排序
CoreData:注释:sql执行时间:0.0007s
CoreData:注释:从连接表中预取多对多关系"发送者"来自数据库。有6行
CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZPROFILEPHOTO,t0.ZPROFILEPHOTOLASTCACHEDATE,t0.ZPROFILEPHOTOSOURCE,t0.ZCONTACT,t0.ZUSER从ZCRMADDRESS t0,其中t0.Z_PK IN(?,?,?)
CoreData:注释:sql连接获取时间:0.0004s
CoreData:注释:总获取执行时间:3行为0.0007s。
CoreData:注释:使用密钥发送者预取'。有3排。
CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZCONTENTID,t0.ZCONTENTTYPE,t0.ZDATA,t0.ZDATE,t0.ZEXCHANGEID,t0.ZFILEEXTENSION,t0.ZISLOCAL,t0.ZISTEMPORARY,t0.ZORIGINALFILENAME ,t0.ZSIZEINBYTES,t0.ZTHUMBNAIL,t0.ZMESSAGE,t0.ZUSER from ZCRMATTACHMENT t0 where t0.ZMESSAGE IN(?,?,?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?,?,?,?,?,?,?,?,?,?,?)订单按t0.ZMESSAGE
CoreData:annotation:sql连接获取时间:0.0005s
CoreData:注释:总获取执行时间:0行为0.0007s。
CoreData:注释:使用键'附件预取'。得了0行。
CoreData:sql:SELECT t0.Z_PK,t1.Z_14REPLYTOMESSAGES FROM Z_3REPLYTOMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK = t1.Z_3REPLYTOS WHERE11.Z_14REPLYTOMESSAGES IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,641 t1Z_14REPLYTOMESSAGES ASC的顺序
CoreData:注释:sql执行时间:0.0006s
CoreData:注释:从连接表中预取多对多关系" replyTos"来自数据库。有6行
CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZPROFILEPHOTO,t0.ZPROFILEPHOTOLASTCACHEDATE,t0.ZPROFILEPHOTOSOURCE,t0.ZCONTACT,t0.ZUSER从ZCRMADDRESS t0,其中t0.Z_PK IN(?,?,?)
CoreData:注释:sql连接获取时间:0.0004s
CoreData:注释:总获取执行时间:3行为0.0006s。
CoreData:注释:使用key' replyTos'进行预取。有3排。
CoreData:sql:SELECT t0.Z_PK,t1.Z_14RECIPIENTMESSAGES FROM Z_3RECIPIENTMESSAGES t1 JOIN ZCRMADDRESS t0 ON t0.Z_PK = t1.Z_3RECIPIENTS where t1.Z_14RECIPIENTMESSAGES IN(276,276,276,276,276,276,276,276,276, 286,286,286,286,286,286,286,286,286,624,624,624,624,624,616 t1Z_14RECIPIENTMESSAGES ASC的顺序
CoreData:注释:sql执行时间:0.0006s
CoreData:注释:从连接表中预取多对多关系"收件人"来自数据库。有6行
CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZEMAIL,t0.ZLABEL,t0.ZNAME,t0.ZPRIMARYADDRESS,t0.ZPROFILEPHOTO,t0.ZPROFILEPHOTOLASTCACHEDATE,t0.ZPROFILEPHOTOSOURCE,t0.ZCONTACT,t0.ZUSER从ZCRMADDRESS t0在哪里t0.Z_PK IN(?)
CoreData:注释:sql连接获取时间:0.0004s
CoreData:注释:总获取执行时间:1行为0.0007s。
CoreData:注释:使用键'收件人预取'。有一排。
CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZENCRYPTEDBODY,t0.ZENCRYPTEDHTMLBODY,t0.ZENCRYPTEDPLAINTEXTBODY,t0.ZENCRYPTEDSUBJECT,t0.ZMESSAGE from ZCRMMESSAGEBODY t0 where t0.ZMESSAGE IN(?,?,?,? ,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
CoreData:annotation:sql连接获取时间:0.0011s
CoreData:注释:总获取执行时间:3行为0.0015秒。
CoreData:注释:使用键' messageBody'进行预取。有3排。
CoreData:注释:总获取执行时间:27行为0.1482秒。
答案 0 :(得分:1)
正如Dan Shelly所说,CONTAINS
在谓词中使用不正确。我相信,正如他解释的那样,它仅用于在另一个字符串中查找子字符串。请参阅predicate documentation。但是,出于您的目的,您可以使用子查询。
所以,我会跳到修复中去。您可以将子预测更改为以下内容:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isMarkedForDelete != YES AND isTopReferenceMessage = YES AND SUBQUERY(folders, $folder, $folder = %@).@count != 0 AND account = %@", folder, folder.account];
正如Martin R.所指出的,获取请求不应该两次返回相同的元素。我不知道它为什么会这样,除非它是使用无效谓词的结果。
另外请注意,由于获取请求不应返回重复项,因此returnsDistinctResults
的使用情况与听起来有点不同。您可以找到示例here。