私の手順は次のとおりです。
- TVCを押します。
- 管理オブジェクト コンテキストで新しい FRC を初期化します。
- フェッチを実行します。
- 各セクションに 1 つの行を持つ 2 つのセクションがあります。
- FRCで使用されるフェッチリクエストを実行します。
- 2 つの要素を持つ配列を取得しました。
- 最後の行を削除し、MOC を保存します。
- ポップTVC.
- TVCを押します。
- 同じ MOC で新しい FRC を開始します。
- フェッチを実行します。
- 2 つのセクションを取得しました。
- FRCで使用されるフェッチリクエストを実行します。
- 要素が 1 つの配列を取得しました。
フェッチを実行する前に deleteCacheWithName を呼び出そうとしましたが、成功しませんでした。
何をすべきかわかりません。
クラッシュログ:
2013-01-10 12:27:47.948 MyApp[59830:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[_PFArray objectAtIndex:]: index (1) beyond bounds (1)'
アプリがクラッシュするコード行:
Card *card = [self.fetchedResultsController objectAtIndexPath:indexPath];
以下は、スタンフォード コースの CoreDataTableViewController.m です。
//
// CoreDataTableViewController.m
//
// Created for Stanford CS193p Fall 2011.
// Copyright 2011 Stanford University. All rights reserved.
//
#import "CoreDataTableViewController.h"
@interface CoreDataTableViewController()
@property (nonatomic) BOOL beganUpdates;
@end
@implementation CoreDataTableViewController
#pragma mark - Fetching
- (void)performFetch {
if (self.fetchedResultsController) {
NSLog(@"TVC: Perform fetch");
NSError *error;
[self.fetchedResultsController performFetch:&error];
if (error)
NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
NSLog(@"TVC: Number of fetched objects in FRC: %d", self.fetchedResultsController.fetchedObjects.count);
NSLog(@"TVC: Number of sections in FRC: %d", self.fetchedResultsController.sections.count);
} else {
NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
[self.tableView reloadData];
}
- (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc {
NSFetchedResultsController *oldfrc = _fetchedResultsController;
if (newfrc != oldfrc) {
_fetchedResultsController = newfrc;
newfrc.delegate = self;
if ((!self.title || [self.title isEqualToString:oldfrc.fetchRequest.entity.name]) && (!self.navigationController || !self.navigationItem.title)) {
self.title = newfrc.fetchRequest.entity.name;
}
if (newfrc) {
[self performFetch];
} else {
[self.tableView reloadData];
}
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSUInteger numberOfSections = self.fetchedResultsController.sections.count;
NSLog(@"TVC: DataSource, number of sections: %d", numberOfSections);
return numberOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *sections = self.fetchedResultsController.sections;
if (sections.count == 0) {
NSLog(@"TVC: DataSource, there are no sections");
return 0;
}
id<NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
NSUInteger numberOfRows = sectionInfo.numberOfObjects;
NSLog(@"TVC: DataSource, number of rows: %d, in section: %d", numberOfRows, section);
return numberOfRows;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self.fetchedResultsController sectionIndexTitles];
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) {
[self.tableView beginUpdates];
self.beganUpdates = YES;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type {
if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
{
switch(type)
{
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
if (self.beganUpdates)
[self.tableView endUpdates];
}
- (void)endSuspensionOfUpdatesDueToContextChanges {
_suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
}
- (void)setSuspendAutomaticTrackingOfChangesInManagedObjectContext:(BOOL)suspend {
if (suspend) {
_suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
} else {
[self performSelector:@selector(endSuspensionOfUpdatesDueToContextChanges) withObject:0 afterDelay:0];
}
}
- (void)logFetchedSections:(NSArray *)sections {
}
@end
ここに私のモデルの一部があります:
//
// TLModel.m
//
...
@property (nonatomic, strong) TLCoreData *coreData;
...
- (void)setupFetchedResultsControllerCardsListWithCompletion:(void (^)(NSFetchedResultsController *result))completion {
[self.coreData performWithDocument:^(UIManagedDocument *document) {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Card"];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"named"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)]];
NSError *error;
NSArray *matches = [document.managedObjectContext executeFetchRequest:request error:&error];
NSLog(@"Model: Execute fetch request, array count: %d", matches.count);
NSFetchedResultsController *result = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:document.managedObjectContext
sectionNameKeyPath:@"named"
cacheName:nil];
NSLog(@"Model: Created new FRC: %@", result);
completion(result);
}];
}
...
ここにTVCがあります:
//
// TLMyTableViewController.m
//
...
- (void)prepareFetchedResultController {
[self.model setupFetchedResultsControllerCardsListWithCompletion:^(NSFetchedResultsController *result){
self.fetchedResultsController = result;
}];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"My Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Card *card = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = card.number;
cell.detailTextLabel.text = card.option;
return cell;
}
- (void)viewDidLoad {
NSLog(@"TVC: Did load: %@", self);
[self prepareFetchedResultController];
}
...
TLコアデータ:
//
// TLCoreData.m
//
#import "TLCoreData.h"
#import <CoreData/CoreData.h>
#import "TLManagedDocument.h"
@interface TLCoreData()
@property (nonatomic, strong) TLManagedDocument *document;
@end
@implementation TLCoreData
/*
static TLCoreData *_sharedInstance;
+ (TLCoreData *)sharedDocumentHandler {
static dispatch_once_t once;
dispatch_once(&once, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
*/
- (TLManagedDocument *)document {
if (!_document) {
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"DataUsage.db"];
_document = [[TLManagedDocument alloc] initWithFileURL:url];
}
return _document;
}
- (void)performWithDocument:(OnDocumentReady)onDocumentReady {
void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success) {
if(success) {
#ifdef DEBUG
NSLog(@"Current context: %@", self.document.managedObjectContext);
#endif
onDocumentReady(self.document);
}
#ifdef DEBUG
else
NSLog(@"Core Data: Managed document does not ready");
#endif
};
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]) {
#ifdef DEBUG
NSLog(@"Core Data: Initialized document: %@", self.document.fileURL);
#endif
[self.document saveToURL:self.document.fileURL
forSaveOperation:UIDocumentSaveForCreating
completionHandler:OnDocumentDidLoad];
} else if (self.document.documentState == UIDocumentStateClosed) {
#ifdef DEBUG
NSLog(@"Core Data: Opened document: %@", self.document.fileURL);
#endif
[self.document openWithCompletionHandler:OnDocumentDidLoad];
} else if (self.document.documentState == UIDocumentStateNormal) {
OnDocumentDidLoad(YES);
}
}
- (void)objectsDidChange:(NSNotification *)notification {
#ifdef DEBUG
NSLog(@"Core Data: Objects changed in context: %@", self.document.managedObjectContext);
#endif
}
- (void)contextDidSave:(NSNotification *)notification {
#ifdef DEBUG
NSLog(@"Core Data: Context saved: %@", self.document.managedObjectContext);
#endif
}
- (id)init {
self = [super init];
if (self) {
// Set our document up for automatic migrations
NSDictionary *options = @{
NSMigratePersistentStoresAutomaticallyOption : @YES,
NSInferMappingModelAutomaticallyOption : @YES
};
self.document.persistentStoreOptions = options;
// Register for notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(objectsDidChange:)
name:NSManagedObjectContextObjectsDidChangeNotification
object:self.document.managedObjectContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:self.document.managedObjectContext];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:self.document.managedObjectContext];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextObjectsDidChangeNotification
object:self.document.managedObjectContext];
}
@end
ログは次のとおりです。
2013-01-10 12:27:43.291 MyApp[59830:c07] App: Launched
2013-01-10 12:27:43.354 MyApp[59830:c07] Core Data: Opened document: file://localhost/Users/itsme/Library/Application%20Support/iPhone%20Simulator/6.0/Applications/998028DF-FACC-4EFF-A5C7-B286B91F1100/Documents/DataUsage.db/
2013-01-10 12:27:43.354 MyApp[59830:c07] Model: Logging started
2013-01-10 12:27:43.357 MyApp[59830:c07] App: Did become active
2013-01-10 12:27:43.371 MyApp[59830:c07] Current context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:43.374 MyApp[59830:c07] Current context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:44.746 MyApp[59830:c07] TVC: Did load: <TLMyTableViewController: 0x8566100>
2013-01-10 12:27:44.746 MyApp[59830:c07] Current context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:44.747 MyApp[59830:c07] Model: Execute fetch request, array count: 2
2013-01-10 12:27:44.748 MyApp[59830:c07] Model: Created new FRC: <NSFetchedResultsController: 0x747bbb0>
2013-01-10 12:27:44.748 MyApp[59830:c07] TVC: Perform fetch
2013-01-10 12:27:44.750 MyApp[59830:c07] TVC: Number of fetched objects in FRC: 2
2013-01-10 12:27:44.750 MyApp[59830:c07] TVC: Number of sections in FRC: 2
2013-01-10 12:27:44.751 MyApp[59830:c07] TVC: DataSource, number of sections: 2
2013-01-10 12:27:44.752 MyApp[59830:c07] TVC: DataSource, number of rows: 1, in section: 1
2013-01-10 12:27:44.752 MyApp[59830:c07] TVC: DataSource, number of rows: 1, in section: 0
2013-01-10 12:27:46.346 MyApp[59830:c07] Current context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:46.347 MyApp[59830:c07] Model: Deleting a row
2013-01-10 12:27:46.349 MyApp[59830:c07] TVC: DataSource, number of sections: 1
2013-01-10 12:27:46.349 MyApp[59830:c07] TVC: DataSource, number of sections: 1
2013-01-10 12:27:46.349 MyApp[59830:c07] TVC: DataSource, number of rows: 1, in section: 0
2013-01-10 12:27:46.350 MyApp[59830:c07] Core Data: Objects changed in context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:46.351 MyApp[59830:c07] Core Data: Context saved: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:47.941 MyApp[59830:c07] TVC: Did load: <TLMyTableViewController: 0x747d5e0>
2013-01-10 12:27:47.941 MyApp[59830:c07] Current context: <NSManagedObjectContext: 0x8185590>
2013-01-10 12:27:47.942 MyApp[59830:c07] Model: Execute fetch request, array count: 1
2013-01-10 12:27:47.942 MyApp[59830:c07] Model: Created new FRC: <NSFetchedResultsController: 0x74b9410>
2013-01-10 12:27:47.942 MyApp[59830:c07] TVC: Perform fetch
2013-01-10 12:27:47.944 MyApp[59830:c07] TVC: Number of fetched objects in FRC: 1
2013-01-10 12:27:47.944 MyApp[59830:c07] TVC: Number of sections in FRC: 2
2013-01-10 12:27:47.944 MyApp[59830:c07] TVC: DataSource, number of sections: 2
2013-01-10 12:27:47.945 MyApp[59830:c07] TVC: DataSource, number of rows: 1, in section: 1
2013-01-10 12:27:47.945 MyApp[59830:c07] TVC: DataSource, number of rows: 1, in section: 0
2013-01-10 12:27:47.948 MyApp[59830:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[_PFArray objectAtIndex:]: index (1) beyond bounds (1)'
この行は、配列内のセクションの数が間違っていることを示しています。
2013-01-10 12:27:47.944 MyApp[59830:c07] TVC: Number of sections in FRC: 2
このログのソース コード:
NSLog(@"TVC: Number of sections in FRC: %d", self.fetchedResultsController.sections.count);