奇怪的 NSPredicate 行为?

Posted

技术标签:

【中文标题】奇怪的 NSPredicate 行为?【英文标题】:Weird NSPredicate Behavior? 【发布时间】:2013-08-17 22:57:41 【问题描述】:

我有一个 NSPredicate,它检查一个名为“Eval(whosEval)”的实体的关系,如果该关系 whosEval 与另一个实体的全名“Athlete(evals)”匹配,则它会显示该特定运动员的所有评估。不幸的是,我的谓词正在做奇怪的事情。如果我没有运动员,然后添加一个,然后添加一个评估,它会显示他们的所有评估,然后我添加另一个,第二个运动员不会显示我为该运动员添加的任何评估,而是显示所有其他运动员的评估.我做错了什么吗?在添加 Eval 视图控制器之前显示所有 evals 视图控制器。

allEvals.m

-(void)viewWillAppear:(BOOL)animated

    self.title = [NSString stringWithFormat:@"%@'s Evaluations",_athletesFullName];

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    _managedObjectContext = [appDelegate managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];

    NSFetchRequest *athleteRequest = [[NSFetchRequest alloc] init];

    [athleteRequest setEntity:[NSEntityDescription entityForName:@"Athlete" inManagedObjectContext:_managedObjectContext]];
    NSError *athleteError = nil;
    NSPredicate *athletePredicate = [NSPredicate predicateWithFormat:@"full == %@", _athletesFullName];
    [athleteRequest setPredicate:athletePredicate];
    NSArray *results = [_managedObjectContext executeFetchRequest:athleteRequest error:&athleteError];
    Athlete *currentAthlete = [results objectAtIndex:0];

   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"whosEval == %@", currentAthlete];
   [request setPredicate:predicate];
    NSEntityDescription *eval = [NSEntityDescription entityForName:@"Eval" inManagedObjectContext:_managedObjectContext];
    [request setEntity:eval];



    NSSortDescriptor *sortDescriptor =
    [[NSSortDescriptor alloc] initWithKey:@"date_recorded"
                                ascending:NO
                                 selector:@selector(localizedCaseInsensitiveCompare:)];
    NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];

    NSError *error = nil;
    NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    if (mutableFetchResults == nil)
        //handle error
    

    [self setEvalArray:mutableFetchResults];
    [self.tableView reloadData];


addEval.m

-(void)saveEval

//insert saving attributes here
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        _managedObjectContext = [appDelegate managedObjectContext];
        NSFetchRequest *request = [[NSFetchRequest alloc] init];

        [request setEntity:[NSEntityDescription entityForName:@"Athlete" inManagedObjectContext:_managedObjectContext]];
        NSError *error = nil;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"full == %@", _whichAthletesEval];
        [request setPredicate:predicate];
        NSArray *results = [_managedObjectContext executeFetchRequest:request error:&error];
        Athlete *currentAthlete = [results objectAtIndex:0];

         [eval setWhosEval:currentAthlete];
        NSLog(@"This Eval Belongs to: %@",eval.whosEval);
        NSLog(@"whichAthletesEval value is equal to: %@", _whichAthletesEval);
    
    NSError *error = nil;
    if(![_managedObjectContext save:&error])
        //handle dat error
    
    [self.navigationController popViewControllerAnimated:YES];

【问题讨论】:

【参考方案1】:

我在您的 viewWillAppear: 方法中留下了内联 cmets(以我的姓名首字母签名),指出了我认为是错误的地方。从本质上讲,您获取的是任意运动员而不是被选中的运动员(我假设它是 _athletesFullName 的来源。就您的 saveEval 方法而言,您的命名约定很难遵循,所以我不清楚您还可以在这里遇到什么问题。

-(void)viewWillAppear:(BOOL)animated
    self.title = [NSString stringWithFormat:@"%@'s Evaluations",_athletesFullName];

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    _managedObjectContext = [appDelegate managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];

    NSFetchRequest *athleteRequest = [[NSFetchRequest alloc] init];

    [athleteRequest setEntity:[NSEntityDescription entityForName:@"Athlete" inManagedObjectContext:_managedObjectContext]];
    NSError *athleteError = nil;
    // No predicate is used at all for the contents of results here - see below - CV
    NSArray *results = [_managedObjectContext executeFetchRequest:athleteRequest error:&athleteError];
    NSPredicate *athletePredicate = [NSPredicate predicateWithFormat:@"full == %@", _athletesFullName];
    // This predicate never used as another predicate is set a few lines below - CV
    [request setPredicate:athletePredicate];
    // currentAthlete will not necessarily be the one conforming to athletePredicate
    // just the first in the array of every Athlete you've fetched - CV
    Athlete *currentAthlete = [results objectAtIndex:0];

    // because currentAthlete is arbitrary, you're now creating a predicate you likely didn't intend to - CV
   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"whosEval == %@", currentAthlete];
   [request setPredicate:predicate];
    NSEntityDescription *eval = [NSEntityDescription entityForName:@"Eval" inManagedObjectContext:_managedObjectContext];
    [request setEntity:eval];



    NSSortDescriptor *sortDescriptor =
    [[NSSortDescriptor alloc] initWithKey:@"date_recorded"
                                ascending:NO
                                 selector:@selector(localizedCaseInsensitiveCompare:)];
    NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];

    NSError *error = nil;
    NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    if (mutableFetchResults == nil)
        //handle error
    

    [self setEvalArray:mutableFetchResults];
    [self.tableView reloadData];


【讨论】:

我认为你是对的。我的意思是在我的所有运动员中搜索与所选运动员的属性集匹配的运动员(全名,运动员下的属性为“完整”),但我认为我做错了? 我想我的主要问题是你从哪里得到全名?似乎理想情况下,当一个人选择一个运动员时,对象应该直接传递给这个视图控制器,而不仅仅是运动员的名字。这将消除获取的需要。但是可能还有其他一些不清楚的事情会阻止这种方法。是的,你没有正确地做到这一点——你创建了athleteRequest,设置了实体,然后在没有设置谓词的情况下进行了提取(以防我的 cmets 没有说清楚)。 就是这样!非常感谢!!我将在问题中更新我的代码并接受您的回答。再次感谢! 所以基本上,有 2 个错误。首先是我有一个正确的谓词,我只是根据错误的请求设置它。我把 request(这是 eval 请求)而不是 playerRequest,然后在设置谓词之前获取。更新后的代码现在可以正常工作。再次感谢。 哦,当运动员被选中时,我从运动员表视图中传递了全名,我在下一个视图控制器中使用全名的运动员属性设置了一个属性。这是一个字符串属性。

以上是关于奇怪的 NSPredicate 行为?的主要内容,如果未能解决你的问题,请参考以下文章

NSPredicate 与 NSString 发生奇怪的崩溃

目标c中的电子邮件地址验证

带有 NSPredicate 的 Fetchrequest 不返回正确的值

iOS 核心数据 - NSFetchRequest 和 NSPredicate 不允许双重格式?

CoreData NSPredicate 数学故障

= vs == 在 NSPredicate 中