akr*_*acs 8 iphone predicate core-data nspredicate ios
我正在开发一个iphone应用程序,我与Group和Contact对象建立了一个简单的多对多关系.一个组可以有多个联系人,联系人可以属于多个组.
我正在尝试使用以下谓词选择特定联系人不属于的所有组.(注意:uid字段是我用来唯一标识联系人实体的字符串字段)
[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]
Run Code Online (Sandbox Code Playgroud)
根据Apple的谓词编程指南,ALL聚合操作是有效的,但是我得到以下异常,表明这是一个不受支持的谓词:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate (null)'
Run Code Online (Sandbox Code Playgroud)
我可以使用类似的谓词来使用此谓词选择联系人已经属于的所有组,因此看起来我已正确定义了所有关系和字段.
[NSPredicate predicateWithFormat:@"ANY contacts.uid == %@", contactUId]
Run Code Online (Sandbox Code Playgroud)
在构造谓词时抛出异常,而不是在我尝试实际执行获取请求时抛出异常,因此它似乎与我使用的语法相关,而不是与Core Data支持相关.我究竟做错了什么?
核心数据编程指南说
提取和商店类型之间存在一些交互.在XML,二进制和内存存储中,谓词和排序描述符的评估在Objective-C中执行,可以访问所有Cocoa的功能,包括NSString上的比较方法.另一方面,SQL存储将谓词和排序描述符编译为SQL,并在数据库本身中评估结果.
它继续描述了使用NSPredicate和NSSQLiteStoreType的一些其他限制,但是你在这里使用"ALL"是一个(未记录的)限制,它与fetch请求如何发出SQL有关.
在引擎盖下,CoreData为您的架构生成三个表:
因此,当您调用myGroup.contacts时,会运行以下内容:
select * from Group join JOIN_TABLE on Group.pk == JOIN_TABLE.group_pk join Contact on JOIN_TABLE.contact_pk == Contact.pk where Group.pk == 12
Run Code Online (Sandbox Code Playgroud)
一个点字符背后有很多事情发生!
无论如何,要真正实现您的查询,您需要这样的东西.我在一个实际的SQLite CD数据库上测试了这个,所以表名看起来很奇怪,但它仍然应该是可理解的:
select ZGROUP.Z_PK as outer_pk from ZGROUP where "myUID" not in
(select ZCONTACT.ZUID as contact_uid from ZGROUP join Z_1GROUPS on Z_1GROUPS.Z_2GROUPS == ZGROUP.Z_PK join ZCONTACT on Z_1GROUPS.Z_1CONTACTS == ZCONTACT.Z_PK where ZGROUP.Z_PK == outer_pk)
Run Code Online (Sandbox Code Playgroud)
我不是SQL专家,但我的观察首先是这个查询会很慢,其次是我们开始使用的NSPredicate还有很长的路要走.因此,只有通过大量的努力,CD才能通过SQL查询来完成您想要做的事情,并且它提出的查询不会比ObjC中的天真实现好多少.
无论它的价值如何,Apple开发人员在此声称ALL在SQLite中不受支持,相反的文档是错误的.该文件仍然存在于2013年,因此似乎没有人对此做过任何事情.
无论如何,你应该做的事情是这样的:
NSFetchRequest *fetchRequest = ...
NSArray *result = [moc executeFetchRequest:fetchRequest error:&err];
result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]];
Run Code Online (Sandbox Code Playgroud)
这将评估软件中的谓词.
基本语法没问题。这在我的测试中编译并运行:
NSString *contactUId=@"steve";
NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId];
NSLog(@"p = %@",p);
//=> p = ALL contacts.uid != "steve"
Run Code Online (Sandbox Code Playgroud)
问题很可能出在contactUid变量上。如果它没有值或者没有干净地转换为 NSPredicate 理解的字符串,那么它将导致崩溃。例如
NSString *contactUId;
NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId];
NSLog(@"p = %@",p);
Run Code Online (Sandbox Code Playgroud)
...导致您所描述的崩溃。
我会contactUid在将其分配给谓词之前立即记录,以查看其实际的字符串可转换值是什么。它在 NSLog 中的显示方式就是它在谓词中的显示方式,因为两者都使用相同的字符串格式。