2014-05-11 57 views
1

這是一個奇怪的問題。核心數據不會對已更改的謂詞做出反應

在我的視圖控制器SpieleOrtTVC我將介紹實體Spiel的對象的子集。每次調用視圖控制器時,都應根據用戶在呈現視圖控制器中的選擇顯示不同的子集。

這適用於每次第一次調用視圖控制器。取決於用戶的選擇,獲取的證件會被交給新的視圖控制器,並且正確地到達那裏,正如NSLog證明的那樣。顯示的結果和數據是經過精心設計的。

但是,當視圖控制器被第二次或第三次調用時,正確的獲取條件也被傳遞給視圖控制器,但是,獲取結果對應於之前執行的獲取。

這是代碼。 SpieleOrtTVC被稱爲地圖標註。所選對象的名稱恰好在註釋的標題中,被移交給新實例化的SpieleOrtTVC。

與地圖調用視圖控制器:

- (void)mapView:(MKMapView *)mv annotationView:(MKAnnotationView *)pin calloutAccessoryControlTapped:(UIControl *)control { 

    SpieleOrtTVC *detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:STORYBOARD_ID_SPIELE_ORT]; 

    MKPointAnnotation *theAnnotation = (MKPointAnnotation *) pin.annotation; 

    NSLog(@"the Annotation %@",theAnnotation.title); 

    detailViewController.ortName = theAnnotation.title; 
    detailViewController.stadionName = theAnnotation.subtitle; 

    [self presentViewController:detailViewController animated:YES completion:nil]; 
} 

SpieleOrteTVC.h:

@property (strong, nonatomic) NSString *ortName; 
@property (strong, nonatomic) NSString *stadionName; 

(只是一個屬性,無吸氣劑或setter方法等,自動合成)

這是我對SpieleOrteTVC.m有懷疑的那段代碼:

- (NSManagedObjectContext *) managedObjectContext { 

    if (! _managedObjectContext) { 
     _managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext]; 
    } 

    return _managedObjectContext; 
} 

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    // Edit the entity name as appropriate. 
    NSEntityDescription *entity = [NSEntityDescription entityForName:[self entityName] 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:[self sortDescriptorString] ascending:[self sortAscending]]; 
    NSArray *sortDescriptors = @[sortDescriptor]; 

    [fetchRequest setSortDescriptors:sortDescriptors]; 

    [fetchRequest setPredicate:[self predicate]]; 

    // 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(); 
    } 

    NSLog(@"request: %@", fetchRequest); 
    for (NSManagedObject *mo in [_fetchedResultsController fetchedObjects]) { 
     NSLog(@"fetched: %@", [mo valueForKey:ATTRIB_ANSTOSS]); 
    } 


- (NSString *) entityName { 

    return ENTITY_SPIEL; 
} 

- (NSString *) sortDescriptorString{ 

    return ATTRIB_ANSTOSS; 
} 

- (NSPredicate *) predicate { 

    return [NSPredicate predicateWithFormat:@"(spielOrt.name == %@)", self.ortName]; 
} 

- (BOOL) sortAscending { 
    return YES; 
} 

輸出的第一次通話:

2014-05-11 13:49:16.209 myApp[2745:60b] the Annotation Porto Alegre 
2014-05-11 13:49:21.937 myApp[2745:60b] request: <NSFetchRequest: 0x18c0c960> (entity: Spiel; predicate: (spielOrt.name == "Porto Alegre"); sortDescriptors: ((
    "(anstoss, ascending, compare:)" 
)); batch size: 20; type: NSManagedObjectResultType;) 
2014-05-11 13:49:21.955 myApp[2745:60b] fetched: 2014-06-15 19:00:51 +0000 
2014-05-11 13:49:21.957 myApp[2745:60b] fetched: 2014-06-18 16:00:52 +0000 
2014-05-11 13:49:21.959 myApp[2745:60b] fetched: 2014-06-22 19:00:51 +0000 
2014-05-11 13:49:21.960 myApp[2745:60b] fetched: 2014-06-25 16:00:51 +0000 
2014-05-11 13:49:21.962 myApp[2745:60b] fetched: 2014-06-30 20:00:04 +0000 

而且這是在下次調用的結果,不同的用戶選擇:

2014-05-11 13:50:25.654 myApp[2745:60b] the Annotation Fortaleza 
2014-05-11 13:50:25.675 myApp[2745:60b] request: <NSFetchRequest: 0x18c6c0e0> (entity: Spiel; predicate: (spielOrt.name == "Fortaleza"); sortDescriptors: ((
    "(anstoss, ascending, compare:)" 
)); batch size: 20; type: NSManagedObjectResultType;) 
2014-05-11 13:50:25.681 myApp[2745:60b] fetched: 2014-06-15 19:00:51 +0000 
2014-05-11 13:50:25.683 myApp[2745:60b] fetched: 2014-06-18 16:00:52 +0000 
2014-05-11 13:50:25.684 myApp[2745:60b] fetched: 2014-06-22 19:00:51 +0000 
2014-05-11 13:50:25.686 myApp[2745:60b] fetched: 2014-06-25 16:00:51 +0000 
2014-05-11 13:50:25.687 myApp[2745:60b] fetched: 2014-06-30 20:00:04 +0000 

這清楚地表明,不同的選擇標準是正確服用從用戶的交互中傳遞給新的視圖控制器。特別是獲取請求相應地獲取其謂詞集,但結果在兩種情況下都是相同的。 (此處示例中使用的時間戳對所有對象都是唯一的)

這裏有什麼問題?

我很高興分享到更多的代碼。告訴我你認爲與這個問題有關的東西。

如果這是很重要的:iOS版7.1.1,設備(iPhone 4,4S,5,iPad的迷你 - 都是一樣的)上運行時,Xcode 5.1.1

(我有一個方便的解決方法,但出於好奇,我想知道問題是什麼。)

+1

它可能與緩存有關。嘗試'cacheName:nil'來創建抓取的結果控制器。 –

+0

@MartinR,好主意。與此同時,我觀察到另一個影響。我有另一個視圖控制器,顯示所有這些實體對象的超集。當我去的時候,一切都很好。第一個子集視圖(與上述問題相關的視圖)工作正常,所有後續調用如上所述。當我首先使用子視圖控制器時,那麼顯示超集的視圖控制器只會顯示相同的子集。 –

+0

是的,沒有給出它的緩存名稱似乎工作。感謝提示。您是否認爲這是核心數據中的錯誤? –

回答

7

NSFetchedResultsController參考:

重要:如果您使用的是高速緩存,則必須調用 deleteCacheWithName:改變任何讀取請求時,其謂語 ,或者它的排序描述符之前。除非將 cacheName設置爲nil,否則不得重複使用同一個 提取的結果控制器進行多個查詢。

因此,您的情況的問題是,FRC重新使用爲不同的謂詞創建的緩存。在創建新FRC之前,請勿使用緩存(cacheName:nil)或刪除 緩存。在你的情況下,緩存可能不會使 有意義。

+0

這是正確的。那麼,我沒有使用SAME NSFetchedResultsController。對於每個不同的請求,它都會隨着其擁有的視圖控制器而立即新增。以及這個其他視圖控制器instanciates自己的NSFetchedResultsController的實例。但是,它們都共享相同的緩存。對,如果我真的需要爲每個請求創建一個新緩存,緩存根本就沒有意義。 –

+0

@HermannKlecker:文檔不是很清楚。我認爲從FRC文檔中的「Cache」段落可以得出結論,它也適用於新的FRC實例。否則,你根本就不需要緩存。 –

+0

沒錯。但是,一般來說,緩存中的含義是什麼,每當新請求可能與同一個實體相關時(這就是兌現方式,其性能收益來自何處),但是具有不同的獲取標準時,謂語)?這些緩存永遠不能共享交叉類或甚至對象,因爲一個對象無法知道另一個對象曾對此緩存做過什麼。有點呃。 –