【问题标题】:Core Data to-many relationship fetching核心数据对多关系获取
【发布时间】:2014-07-10 00:43:41
【问题描述】:

我在核心数据中设置了以下内容:包含许多成分的 Dish 实体和包含一个菜的成分实体。

我无法获取我的一对多关系数据,即某道菜的配料。我正在尝试使用与每道菜相关的成分填充我的收藏视图单元格。

我的核心数据模型设置如下:

我尝试了各种方法来获取数据。

我尝试过的事情之一是执行以下操作:Dish *dish = [self.fetchedResultsController objectAtIndexPath:indexPath];,然后是 NSLog disc.ingredients(它返回一个 NSSet),但返回整个核心数据项,即 createdAt 日期、名称以及所有内容,以及该菜的未格式化版本的配料。

我尝试的另一件事是使用Ingredient *ingredient = [dish.ingredients valueForKeyPath:@"ingredientName"]; 创建成分实体的新实例,但这会返回一个未格式化的字符串(我希望它在显示之前对其进行 UTF8 编码,因为它包含特殊字符)。

谷歌搜索时有很多解决方案建议使用 NSPredicate,但我就是不知道如何使用它。我对核心数据和 XCODE 还是很陌生,所以这里的任何帮助都将不胜感激,即你在哪里实现 NSPredicate,在我的情况下正确的谓词是什么?

一点支持代码:

我的 collectionViewController:

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSManagedObjectContext* context = [RKObjectManager sharedManager].managedObjectStore.mainQueueManagedObjectContext;
    self.managedObjectContext = context;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dish" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createdAt" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _fetchedResultsController;
}

cellForItemAtIndexPath:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    FOFPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photo" forIndexPath:indexPath];

    self.object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    Dish *dish = [self.fetchedResultsController objectAtIndexPath:indexPath];

    Ingredient *ingredient = ???;
    cell.backgroundColor = [UIColor lightGrayColor];





    [cell.imageView setImageWithURL:[NSURL URLWithString:[[NSString stringWithFormat:@"http://192.168.0.3:4000%@", dish.dishImage] description]] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
    }];

    cell.titleLabel.text = dish.dishName;
    cell.headerLabel.text = dish.dishHeader;


    cell.ingredientsLabel.text = [NSString stringWithFormat:@"%@", nil];

    NSLog(@"%@", ingredient);


    [self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];

    return cell;
}

【问题讨论】:

    标签: ios objective-c core-data


    【解决方案1】:

    简单的方法是你的第一种方法,然后只使用你关心的成分的属性。 Core Data 更多的是关于对象编程而不是底层数据库,因此尝试模拟 DB 查询通常不是正确的方法。

    我还建议去掉所有 valueForKey 的东西并使用实际的对象属性,这样代码会更清晰,编译器可以在数据类型方面为您提供更多帮助。

    【讨论】:

    • 感谢@Phillip 的回复,正如您所说,我已重构代码以删除大部分 ValueForKey。我似乎无法弄清楚如何正确地实例化我的成分模型,你能指出我如何做到这一点的正确方向吗?
    • 嗯,正如您所指出的,任何菜肴的成分都表示为一组。由此,我不明白你想用Ingredient *ingredient = ???; 获得哪种成分。您想将哪些实际信息放入ingredientsLabel? …一种成分名称? ......所有成分名称的累积? ……其他?
    • 我想将所有成分名称的单位和值放在标签中以显示给定菜肴。我以为我必须像使用 Dish 模型一样实例化我的 Ingredient 模型?
    • 并非如此,当您实例化您的Dish 时,您会得到它与它的关系。我建议创建一个方法,将Dish 传递给它并返回NSString,您可以通过循环遍历其每个成分(在集合中)并挑选出您想要的信息来构建该方法。
    • 好的,所以基本上我会创建一个for 循环并遍历 NSSet 并提取成分?我会试试的
    【解决方案2】:

    如果您只为一种特定的菜肴寻找成分,您必须为成分(而不是菜肴)设置您的 fetchRequest,并在菜肴上设置谓词。要使以下代码正常工作,您可能需要首先创建 NSManagedObject 子类(借助 Xcode 编辑器按钮)。

    #import "Dish.h"
    #import "Ingredient.h"
    
    - (NSFetchedResultsController *)fetchedResultsController
    {
        if (_fetchedResultsController != nil) {
            return _fetchedResultsController;
        }
    
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Ingredient"];
        [fetchRequest setFetchBatchSize:20];
    
        //if dishname are unique values, set your predicate on it.
        //You can also set your predicate on the dishID if dishName are not unique values (several dishes with a same name)
        NSString *theDishIWant = @"Ratatouille"; //whatever Dish name you want
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dish.dishName == %@", theDishIWant];
        [fetchRequest setPredicate:predicate];
    
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"ingredientname" ascending:YES];
        [fetchRequest setSortDescriptors:@[sortDescriptor];
    
        NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[RKObjectManager sharedManager].managedObjectStore.mainQueueManagedObjectContext sectionNameKeyPath:nil cacheName:nil];
    
        aFetchedResultsController.delegate = self;
        self.fetchedResultsController = aFetchedResultsController;
    
        NSError *error = nil;
        if (![self.fetchedResultsController performFetch:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    
    NSLog (@"%@", _fetchedResultsController);
    return _fetchedResultsController;
    }
    

    您的configureCell: atIndexPath: 方法可能如下所示:

    - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
    {
        Ingredient *ingredient = [self.fetchedResultsController objectAtIndexPath:indexPath];
    
        cell.textLabel.text = ingredient.ingredientName;
        cell.detailTextLabel.text = ingredient.ingredientValue;
    }
    

    【讨论】:

    • 我是否正确地认为如果我这样做,我将无法用菜肴的配料自动填充我的所有单元格? (每道菜都以网格视图显示)
    猜你喜欢
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    相关资源
    最近更新 更多