核心数据:为什么我无法使用谓词获取任何内容

时间:2012-09-24 17:52:43

标签: objective-c core-data

代码有问题吗?我可以使用这个谓词取任何东西。注释掉谓词然后我可以从实体“BankDetail”中获取所有对象。所以我认为问题在于这两行。

// self.bankInfo.name is set in prepareForSegue in first view controller
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"info.name = %@",self.bankInfo.name];
[request setPredicate:predicate];

我的模型包含两个实体,它们是一对一的关系

BankInfo.h

@class BankDetail;

@interface BankInfo : NSManagedObject

@property (nonatomic, retain) NSString * city;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * state;
@property (nonatomic, retain) BankDetail * detail;

@end

BankDetail.h

@class BankInfo;

@interface BankDetail : NSManagedObject

@property (nonatomic, retain) NSString * closeDate;
@property (nonatomic, retain) NSString * updateDate;
@property (nonatomic, retain) NSString * zip;
@property (nonatomic, retain) NSString * acquiringInstitution;
@property (nonatomic, retain) BankInfo * info;

@end

修改

提供更多细节:

  • self.bankInfo.name肯定已设置,我在谓词行之前将其存储

  • 我在viewDidLoad中执行此操作:

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"BankDetail" inManagedObjectContext:context];
    NSLog(@"[entity description] is %@",[entity description]);
    

在控制台中获取此内容:

info = "(<NSRelationshipDescription: 0x6d3eb30>), name info, isOptional 1, isTransient 0, entity BankDetail, renamingIdentifier info, validation predicates (\n), warnings (\n), versionHashModifier (null)\n userInfo {\n}, destination entity BankInfo, inverseRelationship detail, minCount 1, maxCount 1, isOrdered 0, deleteRule 2";

EDIT2: 结果是谓词没有错误。这个错误是由其他地方的粗心错误引起的(参见接受的答案,它是关于重命名)。如果您对谓词有疑问,请点击这篇文章。

7 个答案:

答案 0 :(得分:1)

如果它是一对一的关系,并且您已经拥有要匹配的self.bankInfo.name字符串,为什么不提取具有该名称的BankInfo对象并访问该对象.detail财产?这是建立关系的重点,不是吗?

但是,你的谓词应该有效。但self.bankInfo是什么?您确定self.bankinfo.name是有效的字符串吗?

答案 1 :(得分:1)

你的谓词结构没问题。请参阅我的其他answer,了解一个简单的项目来证明基本原理。

根据对其他答案的回答,您可能会将此NSFetchRequest传递给NSFetchedResultsController并使用其行为来确定您的谓词不起作用。

我的第一个建议是记录谓词并查看它是否符合预期:

NSLog(@"%@", predicate);

如果可以,那么为了测试谓词不起作用的理论,你应该在构建请求后立即直接执行NSFetchRequest,并检查结果,例如

// self.bankInfo.name is set in prepareForSegue in first view controller
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"info.name = %@",self.bankInfo.name];
[request setPredicate:predicate];

NSArray *results = [myMangedObjectContext executeFetchRequest:request error:nil];

如果这没有说明问题,那么我建议您从请求中删除谓词,执行请求,并使用以下日志语句来检查完整结果:

NSLog(@"%@", self.bankInfo.name);
NSLog(@"%@", [results valueForKeyPath:@"info.name"]);

最后一条日志语句实际记录了所有银行名称的数组,因此您可以查看self.bankInfo.name中的值是否出现在您想要的完整结果中。

答案 2 :(得分:0)

最后,我必须使用一个不那么优雅的解决方法。我最终也为name添加了BankDetail属性。因此,一个BankInfo.name对应一个BankDetail.name。然后我使用谓词:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@",self.bankInfo.name];

它可以实现我想要的:为相应的BankDetail对象获取一个BankInfo对象。我不知道这是最好的做法..

答案 3 :(得分:0)

据我所知,你的谓词没有任何问题。我在我的应用程序中有一个非常相似的,它工作正常:

@class Hospital;

@interface Patient : NSManagedObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) Hospital *hospital;

@end

@class Patient;

@interface Hospital : NSManagedObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSSet *patients;

@end

我的谓词:

request.predicate = [NSPredicate predicateWithFormat:@"hospital.name = %@", self.hospital.name];

所以你的代码没有问题。问题必须是因为self.bankInfoself.bankInfo.name为空,或者因为info对象中BankDetail中没有任何内容(未设置关系)。

答案 4 :(得分:0)

您最初发布的谓词代码是正确的。下面是一个测试基本原理的快速测试项目:(正确记录“银行名称”)

// Xcode 4.5:
// Create a new iOS Master-Detail project called "BankInfoTest" tick the "Use Core Data" check box (and ARC).
// Delete all files except the AppDelegate and the BankInfoTest data model (leave supporting files).
// Delete all properties and methods from AppDelegate.h
// Paste this code into AppDelegate.m
// Delete the default entity from the data model
// Add "BankInfo" entity, add attribute "name" of type string.
// Add "BankDetail" entity, add relationship called "info" to BankInfo (leave default 1 to 1 type).
// On BankInfo entity add inverse relationship "detail" to BankDetail (leave default 1 to 1 type).
// Select both entities then select "Editor -> Create NSManagedObject Subclass" to create subclasses.
// Run.

#import "AppDelegate.h"
#import "BankDetail.h"
#import "BankInfo.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    /////////////////////////////////////////////////////////////////////////////////////
    // Setup the core data stack.
    /////////////////////////////////////////////////////////////////////////////////////
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"BankInfoTest" withExtension:@"momd"];
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    NSURL *appDocsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [appDocsDirectory URLByAppendingPathComponent:@"BankInfoTest"];

    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:nil];

    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    context.persistentStoreCoordinator = coordinator;


    /////////////////////////////////////////////////////////////////////////////////////
    // Load some test data and reset the context.
    /////////////////////////////////////////////////////////////////////////////////////
    BankDetail *detailObject = [NSEntityDescription insertNewObjectForEntityForName:@"BankDetail" inManagedObjectContext:context];
    BankInfo *infoObject = [NSEntityDescription insertNewObjectForEntityForName:@"BankInfo" inManagedObjectContext:context];

    infoObject.name = @"bank name";
    detailObject.info = infoObject;

    [context save:nil];
    [context reset];

    /////////////////////////////////////////////////////////////////////////////////////
    // Test the Predicate
    /////////////////////////////////////////////////////////////////////////////////////
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"BankDetail"];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"info.name = %@", @"bank name"];
    [request setPredicate:predicate];

    NSArray *results = [context executeFetchRequest:request error:nil];
    BankDetail *fetchedObject = [results lastObject];
    NSLog(@"%@", fetchedObject.info.name);

    return YES;
}

@end

答案 5 :(得分:0)

我终于修复了这个bug。它根本不是谓词。我在Xcode编辑器中的.xcdatamodeld中将实体从BankDetails重命名为BankDetail,只需按回车键并更改它,就像重命名任何其他文件一样。

然后我继续手动重命名自动生成的NSManagedObject子类文件中的各个部分,以及引用它的其他类文件,直到所有警告都消失。我想我已经重命名了所有必要的东西,但我没有。该程序没有像我在问题中描述的那样运行,但没有错误,没有警告,Xcode只是编译和运行。

过了一段时间,当我最终尝试重新生成子类文件来修复bug时,旧的BankDetails显示为类名,并且出现了许多命名错误。起初我认为这是Xcode的一些错误。所以我清理构建并再次重新生成子类文件。然而,它仍然是好老BankDetails。经过几次尝试后,我在Data Model Inspector中发现了问题(见下面的截图)。更改班级名称,一切运行完美。

道德:总是极其谨慎地重命名!

enter image description here

答案 6 :(得分:-1)

问题可能是在谓词字符串中使用=运算符。

根据文档,LIKE运算符用于字符串比较,例如

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"info.name like %@",self.bankInfo.name];

该文档还提供了遍历谓词中关系的示例,以便您能够实现所需的结果。来自NSPredicate文档:

  

您可以为关系创建谓词,例如:

     
      
  • group.name喜欢“work *”
  •