2013-01-10 25 views
0

我的步驟是:NSFetchedResultsController錯節的數目

  1. 推TVC。
  2. 使用託管對象上下文初始化新的FRC。
  3. 執行提取。
  4. 在每個部分中有一行有兩個部分。
  5. 執行FRC中使用的提取請求。
  6. 有兩個元素的數組。
  7. 刪除最後一行並保存MOC。
  8. Pop TVC。
  9. 推TVC。
  10. 用相同的MOC初始化新的FRC。
  11. 執行提取。
  12. 有兩個部分。
  13. 執行FRC中使用的提取請求。
  14. 有一個元素的數組。

我試圖在未成功執行提取前調用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]; 
} 

... 

TLCoreData:

// 
// 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); 
+0

提供一些代碼,請。 –

+0

我正在嘗試簡化源代碼,請等待,請 – adnako

+0

試試我寫的解決方案。謝謝。 –

回答

0

你應該爲我們提供其他細節。

在此期間,我真的建議看看NSFetchedResultsControllerDelegate班。你可以在類參考中找到你需要實現的方法。

如果設置委託爲您NSFetchedResultsController例如像

_fetchedController.delegate = self; 

屆時,代表將要到核心數據模型所做的變化做出反應(添加或刪除的部分,添加,刪除,移動或更新行) 。

例如,如果您實現

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
    atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 

    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
          withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
          withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

,並刪除或添加一節,更改將被捕獲爲您服務。

希望它有幫助。

編輯

我的猜測是,如果TLMyTableViewController延伸CoreDataTableViewController,你是不是調用

- (void)prepareFetchedResultController { 
    [self.model setupFetchedResultsControllerCardsListWithCompletion:^(NSFetchedResultsController *result){ 
     self.fetchedResultsController = result; 
    }]; 
} 

嘗試正確的方法來使用,而不是

[self setFetchedResultsController:result]; 
+0

感謝您的建議。 – adnako

+0

我在FRC的setter中設置了委託,它調用了didChangeSection方法。 編輯過的TVC中一切正常。 然後我彈出編輯過的TVC,並用新的FRC推送新的(但用相同的MOC初始化)。 而新的TVC無法顯示自己,因爲FRC給出了錯誤數目的部分的數組。 – adnako

+0

@cirroz提供一些代碼。因爲很難理解正在發生的事情。同時刪除日誌並添加相關代碼。謝謝。 –

相關問題