核心数据错误“获取请求必须具有实体”

时间:2010-03-29 00:57:17

标签: iphone parsing uitableview core-data

我尝试将TopSongs解析器和核心数据文件添加到我的应用程序中,现在它已成功构建,没有错误或警告消息。但是,只要应用程序加载,它就会崩溃,原因如下:

更新:我已经完成了所有工作,但我的TableView没有显示任何数据,并且应用程序不响应以下断点。

感谢。

更新:这是不响应断点的新代码。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)table {
    return [[fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

- (void)viewDidUnload {
    [super viewDidUnload];
    self.tableView = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.managedObjectContext];
    [self.tableView reloadData]; 
}

- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellIdentifier = @"SongCell";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
    }
    Incident *incident = [fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"#%d %@", @"#%d %@"), incident.title];
    return cell;
}

- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [table deselectRowAtIndexPath:indexPath animated:YES];
    self.detailController.incident = [fetchedResultsController objectAtIndexPath:indexPath];
    [self.navigationController pushViewController:self.detailController animated:YES];
}

更新:这是找到所有fetch实例的代码。

- (Category *)categoryWithName:(NSString *)name {
    NSTimeInterval before = [NSDate timeIntervalSinceReferenceDate];
#ifdef USE_CACHING
    // check cache
    CacheNode *cacheNode = [cache objectForKey:name];
    if (cacheNode != nil) {
        // cache hit, update access counter
        cacheNode.accessCounter = accessCounter++;
        Category *category = (Category *)[managedObjectContext objectWithID:cacheNode.objectID];
        totalCacheHitCost += ([NSDate timeIntervalSinceReferenceDate] - before);
        cacheHitCount++;
        return category;
    }
#endif
    // cache missed, fetch from store - if not found in store there is no category object for the name and we must create one
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:self.categoryEntityDescription];
    NSPredicate *predicate = [self.categoryNamePredicateTemplate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObject:name forKey:kCategoryNameSubstitutionVariable]];
    [fetchRequest setPredicate:predicate];
    NSError *error = nil;
    NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];
    NSAssert1(fetchResults != nil, @"Unhandled error executing fetch request in import thread: %@", [error localizedDescription]);

    Category *category = nil;
    if ([fetchResults count] > 0) {
        // get category from fetch
        category = [fetchResults objectAtIndex:0];
    } else if ([fetchResults count] == 0) {
        // category not in store, must create a new category object 
        category = [[Category alloc] initWithEntity:self.categoryEntityDescription insertIntoManagedObjectContext:managedObjectContext];
        category.name = name;
        [category autorelease];
    }
#ifdef USE_CACHING
    // add to cache
    // first check to see if cache is full
    if ([cache count] >= cacheSize) {
        // evict least recently used (LRU) item from cache
        NSUInteger oldestAccessCount = UINT_MAX;
        NSString *key = nil, *keyOfOldestCacheNode = nil;
        for (key in cache) {
            CacheNode *tmpNode = [cache objectForKey:key];
            if (tmpNode.accessCounter < oldestAccessCount) {
                oldestAccessCount = tmpNode.accessCounter;
                [keyOfOldestCacheNode release];
                keyOfOldestCacheNode = [key retain];
            }
        }
        // retain the cache node for reuse
        cacheNode = [[cache objectForKey:keyOfOldestCacheNode] retain];
        // remove from the cache
        [cache removeObjectForKey:keyOfOldestCacheNode];
    } else {
        // create a new cache node
        cacheNode = [[CacheNode alloc] init];
    }
    cacheNode.objectID = [category objectID];
    cacheNode.accessCounter = accessCounter++;
    [cache setObject:cacheNode forKey:name];
    [cacheNode release];
#endif
    totalCacheMissCost += ([NSDate timeIntervalSinceReferenceDate] - before);
    cacheMissCount++;
    return category;
}

这一个......

- (void)fetch {
    NSError *error = nil;
    BOOL success = [self.fetchedResultsController performFetch:&error];
    NSAssert2(success, @"Unhandled error performing fetch at SongsViewController.m, line %d: %@", __LINE__, [error localizedDescription]);
    [self.tableView reloadData];
}

- (NSFetchedResultsController *)fetchedResultsController {
    if (fetchedResultsController == nil) {
        NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
        [fetchRequest setEntity:[NSEntityDescription entityForName:@"Song" inManagedObjectContext:managedObjectContext]];
        NSArray *sortDescriptors = nil;
        NSString *sectionNameKeyPath = nil;
        if ([fetchSectioningControl selectedSegmentIndex] == 1) {
            sortDescriptors = [NSArray arrayWithObjects:[[[NSSortDescriptor alloc] initWithKey:@"category.name" ascending:YES] autorelease], [[[NSSortDescriptor alloc] initWithKey:@"rank" ascending:YES] autorelease], nil];
            sectionNameKeyPath = @"category.name";
        } else {
            sortDescriptors = [NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"rank" ascending:YES] autorelease]];
        }
        [fetchRequest setSortDescriptors:sortDescriptors];
        fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionNameKeyPath cacheName:@"SongsCache"];
    }    
    return fetchedResultsController;
} 

4 个答案:

答案 0 :(得分:0)

基于发布的代码和问题描述,我怀疑categoryEntityDescription属性返回nil。

答案 1 :(得分:0)

  1. 您的额外缓存可能会浪费周期,因为Core Data会在内部执行自己的缓存。我愿意打赌你放慢速度而不是加快速度,更不用说你正在消耗的额外内存。

  2. 您在哪里设置categoryEntityDescription?现在显示在您发布的代码中。这可能是零。

  3. 为什么要保留NSEntityDescription?!?它们已经因为核心数据而处于内存状态,如果Core Data希望在某些时候发布它,那么保留它们可能会导致问题。

  4. 更新

    您的缓存绝对不是来自Apple的代码,因为他们知道缓存是在Core Data中。

    对于NSEntityDescription,再次 保留NSEntityDescription

    您是否100%肯定NSEntityDescription不是零?你在调试器中确认了吗?您是否使用刚刚检索过的NSEntityDescription

    对其进行了测试

    更新

    您需要学习使用调试器,因为这将解决您的大多数编码问题。在此方法中放置一个断点并在调试器中运行代码。然后,当执行在该断点处停止时,您可以检查变量的值并了解它们当前设置的内容。这将证实或否认你对什么是和不是的怀疑。

    当您未能在Entity中设置NSFetchRequest时,您会看到此错误,根据您的代码,这意味着在您显示的代码出现之前未设置保留属性调用。

答案 2 :(得分:0)

由于您手动添加了模型文件,因此目标中Compile Sources步骤中的.xcdatamodel文件是什么?

转到群组&amp;中的目标条目Xcode中的文件窗格,然后单击显示三角形。然后单击您的应用程序的显示三角形。然后检查它是否在Compile Sources中。如果没有,请右键单击Compile Sources并选择“Add - &gt; Existing File ...”并添加它。

根据更新进行修改:

  

更新:这是新代码   没有回应断点。

- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath

您的视图控制器是否设置为UITableViewDataSource的{​​{1}} / UITableViewDelegate?如果没有,这些方法将不会被调用。

答案 3 :(得分:0)

我已经看到,当提取请求的NSEntityDescription为零时会发生这种情况。最可能的原因是您的模型实体的名称与您提供给entityForName的名称不同。除此之外,它可能是配置Core Data堆栈或缺少数据模型时出错,但作为第一步,我建议将entityForName的结果存储在局部变量中并在那里确保它不是零。