【发布时间】:2014-02-24 19:45:04
【问题描述】:
我正在使用 NSFetchedResultsController 将不同电子邮件帐户的消息加载到表格视图和集合视图中。在 iOS7 上一切都很好,在 iOS6 中一切都很好,除了我使用组合 OR 谓词。
现在我知道,如果 NSFetchedResultsController 匹配多个这些谓词,它将返回相同的项目两次。我的问题是消息实体仅匹配这些谓词之一,但返回的次数与谓词相同。
因此,出于某种原因,NSFetchedResultsController 说这些消息传递了所有谓词,但仅在 iOS6 上。它针对来自特定电子邮件帐户的每条消息执行此操作,但不针对来自其他帐户的消息。
如果我将 OR 谓词调整为不使用 ObjectID,则会返回唯一结果。但是,随着值的调整,我的 UI 将不再正确更新
在我的一生中,我似乎无法弄清楚这些实体究竟是如何为其他电子邮件帐户和文件夹传递谓词的。
我的导致重复的谓词构造如下。 Account -> messages 是 oneToMany 关系,文件夹 messages 是 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];
因此,如果我将其更改为像这样的 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
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, 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.REFLEXIVE IN (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.REFLEXIVE 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, 624, 624, 624, 624 ) ORDER BY t1.Z_14CARBONCOPYMESSAGES 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, 6,276,72 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 FROM ZCRMADDRESS t0 WHERE t0.Z_PK IN (?,?,?)
CoreData:注解:sql连接获取时间:0.0004s
CoreData:注释:总提取执行时间:3 行 0.0007 秒。
CoreData:注释:使用密钥“发送者”预取。有3行。
核心数据: 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 来自 ZCRMATTACHMENT t0 WHERE t0.ZMESSAGE IN (?,?,?,?,?,?,?,?,?,?,?,?,? ,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY t0.ZMESSAGE
CoreData:注解:sql连接获取时间:0.0005s
CoreData:注释:总提取执行时间:0 行 0.0007 秒。
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 WHERE t1.Z_14REPLYTOMESSAGES IN ( 276, 276, 276, 7, 276, 7, 276, 6, 6, 276, 6, 286, 286, 286, 286, 286, 286, 286, 286, 286, 624, 624, 624, 624, 624, 624, 624, 624, 624 ) ORDER BY t1.Z_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 FROM ZCRMADDRESS t0 WHERE t0.Z_PK IN (?,?,?)
CoreData:注解:sql连接获取时间:0.0004s
CoreData:注释:总提取执行时间:3 行 0.0006 秒。
CoreData:注释:使用键“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,6,276,7,276,7,27 286, 286, 286, 286, 286, 286, 286, 286, 286, 624, 624, 624, 624, 624, 624, 624, 624, 624 ) ORDER BY t1.Z_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 WHERE t0.Z_PK IN (?)
CoreData:注解:sql连接获取时间:0.0004s
CoreData:注释:总提取执行时间:1 行 0.0007 秒。
CoreData:注释:使用密钥“收件人”进行预取。有 1 行。
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:注解:sql连接获取时间:0.0011s
CoreData:注释:总提取执行时间:3 行 0.0015 秒。
CoreData:注释:使用键“messageBody”预取。有3行。
CoreData:注释:总提取执行时间:27 行 0.1482 秒。
【问题讨论】:
-
重复项是什么意思? FRC 不会两次返回相同的元素。
-
是的,它使用多个谓词。它们是完全相同的 NSManagedObject,NSFetchedResultsController 多次返回相同的永久 ID
-
我也检查了SQL DB,只有一个条目
-
打开 Core Data 的 SQLite 调试以查看到底发生了什么会很有用,如下所述:nshipster.com/launch-arguments-and-environment-variables
-
folders contains ...是错误的谓词用法。 contains 仅对字符串值匹配有效。
标签: ios sql core-data predicate nsfetchedresultscontroller