2012-12-24 11 views
13
  1. मैं पॉप्युलेट और save: अपडेट के बाद एक प्रारंभिक NSManagedObjectContext
  2. सेटअप भिन्न NSManagedObjectContext के साथ एक NSFetchedResultsController है, जो एक boolean "शो" विशेषता पर फिल्टर।
  3. अंततः एक और NSManagedObjectContext और save: पर "शो" अपडेट करें।

मैं उम्मीद करते हैं कि यह मेरा NSFetchedResultsController कॉल करने के लिए NSFetchedResultsControllerDelegate के controllerDidChangeContent: कारण चाहिए। मुझे वह कॉल कभी नहीं मिला। NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext का accepted answer इंगित करता है कि controllerDidChangeContent: के अतिरिक्त, मुझे NSManagedObjectContextObjectsDidChangeNotification मिलना चाहिए, लेकिन मुझे यह भी प्राप्त नहीं होता है।NSFetchedResultsController controllerDidChangeContent फोन नहीं करता है: करने के लिए गैर-प्राप्त किए गए NSManagedObject

एक पूर्ण कोड उदाहरण नीचे दिया गया है और on githubI've filed a radar with Apple

@interface HJBFoo : NSManagedObject 

@property (nonatomic, retain) NSString *name; 
@property (nonatomic, retain) NSNumber *show; 

@end 

@interface HJBAppDelegate() <NSFetchedResultsControllerDelegate> 

@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator; 
@property (nonatomic, strong) NSManagedObjectContext *initialManagedObjectContext; 
@property (nonatomic, strong) NSManagedObjectContext *fetchedResultsControllerManagedObjectContext; 
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController; 

@end 

@implementation HJBAppDelegate 

#pragma mark - UIApplicationDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    self.window.backgroundColor = [UIColor whiteColor]; 
    self.window.rootViewController = [UIViewController new]; 

    NSAttributeDescription *nameAttributeDescription = [NSAttributeDescription new]; 
    [nameAttributeDescription setAttributeType:NSStringAttributeType]; 
    [nameAttributeDescription setIndexed:NO]; 
    [nameAttributeDescription setOptional:NO]; 
    [nameAttributeDescription setName:@"name"]; 

    NSAttributeDescription *showAttributeDescription = [NSAttributeDescription new]; 
    [showAttributeDescription setAttributeType:NSBooleanAttributeType]; 
    [showAttributeDescription setIndexed:YES]; 
    [showAttributeDescription setOptional:NO]; 
    [showAttributeDescription setName:@"show"]; 

    NSEntityDescription *fooEntityDescription = [NSEntityDescription new]; 
    [fooEntityDescription setManagedObjectClassName:@"HJBFoo"]; 
    [fooEntityDescription setName:@"HJBFoo"]; 
    [fooEntityDescription setProperties:@[ 
    nameAttributeDescription, 
    showAttributeDescription, 
    ]]; 

    NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel new]; 
    [managedObjectModel setEntities:@[ 
    fooEntityDescription, 
    ]]; 

    self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; 
    NSError *error = nil; 
    if ([self.persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType 
                 configuration:nil 
                   URL:nil 
                  options:nil 
                   error:&error]) { 
     self.initialManagedObjectContext = [NSManagedObjectContext new]; 
     [self.initialManagedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 

     HJBFoo *foo1 = [NSEntityDescription insertNewObjectForEntityForName:@"HJBFoo" 
                inManagedObjectContext:self.initialManagedObjectContext]; 
     foo1.name = @"1"; 
     foo1.show = @YES; 

     HJBFoo *foo2 = [NSEntityDescription insertNewObjectForEntityForName:@"HJBFoo" 
                inManagedObjectContext:self.initialManagedObjectContext]; 
     foo2.name = @"2"; 
     foo2.show = @NO; 

     error = nil; 
     if ([self.initialManagedObjectContext save:&error]) { 
      NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"HJBFoo"]; 
      [fetchRequest setReturnsObjectsAsFaults:NO]; 

      error = nil; 
      NSArray *initialFoos = [self.initialManagedObjectContext executeFetchRequest:fetchRequest 
                        error:&error]; 
      if (initialFoos) { 
       NSLog(@"Initial: %@", initialFoos); 

       self.fetchedResultsControllerManagedObjectContext = [NSManagedObjectContext new]; 
       [self.fetchedResultsControllerManagedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 

       NSFetchRequest *shownFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"HJBFoo"]; 
       [shownFetchRequest setPredicate:[NSPredicate predicateWithFormat:@"show == YES"]]; 
       [shownFetchRequest setSortDescriptors:@[ 
       [NSSortDescriptor sortDescriptorWithKey:@"name" 
               ascending:YES], 
       ]]; 

       self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:shownFetchRequest 
                        managedObjectContext:self.fetchedResultsControllerManagedObjectContext 
                         sectionNameKeyPath:nil 
                           cacheName:nil]; 
       self.fetchedResultsController.delegate = self; 
       error = nil; 
       if ([self.fetchedResultsController performFetch:&error]) { 
        NSLog(@"Initial fetchedObjects: %@", [self.fetchedResultsController fetchedObjects]); 

        [[NSNotificationCenter defaultCenter] addObserver:self 
                  selector:@selector(managedObjectContextDidSave:) 
                   name:NSManagedObjectContextDidSaveNotification 
                   object:nil]; 
        [[NSNotificationCenter defaultCenter] addObserver:self 
                  selector:@selector(managedObjectContext2ObjectsDidChange:) 
                   name:NSManagedObjectContextObjectsDidChangeNotification 
                   object:self.fetchedResultsControllerManagedObjectContext]; 

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), 
            dispatch_get_main_queue(), 
            ^(void){ 
             NSManagedObjectContext *managedObjectContext3 = [NSManagedObjectContext new]; 
             [managedObjectContext3 setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 

             NSFetchRequest *foo2FetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"HJBFoo"]; 
             [foo2FetchRequest setFetchLimit:1]; 
             [foo2FetchRequest setPredicate:[NSPredicate predicateWithFormat:@"name == %@", 
                     @"2"]]; 
             NSError *editingError = nil; 
             NSArray *editingFoos = [managedObjectContext3 executeFetchRequest:foo2FetchRequest 
                            error:&editingError]; 
             if (editingFoos) { 
              HJBFoo *editingFoo2 = [editingFoos objectAtIndex:0]; 
              editingFoo2.show = @YES; 

              editingError = nil; 
              if ([managedObjectContext3 save:&editingError]) { 
               NSLog(@"Save succeeded. Expected (in order) managedObjectContextDidSave, controllerDidChangeContent, managedObjectContext2ObjectsDidChange"); 
              } else { 
               NSLog(@"Editing save failed: %@ %@", [error localizedDescription], [error userInfo]); 
              } 
             } else { 
              NSLog(@"Editing fetch failed: %@ %@", [error localizedDescription], [error userInfo]); 
             } 

            }); 
       } else { 
        NSLog(@"Failed initial fetch: %@ %@", [error localizedDescription], [error userInfo]); 
       } 
      } else { 
       NSLog(@"Failed to performFetch: %@ %@", [error localizedDescription], [error userInfo]); 
      } 
     } else { 
      NSLog(@"Failed to save initial state: %@ %@", [error localizedDescription], [error userInfo]); 
     } 
    } else { 
     NSLog(@"Failed to add persistent store: %@ %@", [error localizedDescription], [error userInfo]); 
    } 

    [self.window makeKeyAndVisible]; 
    return YES; 
} 

#pragma mark - NSFetchedResultsControllerDelegate 

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    NSLog(@"controllerDidChangeContent: %@", 
      [self.fetchedResultsController fetchedObjects]); 
} 

#pragma mark - notifications 

- (void)managedObjectContextDidSave:(NSNotification *)notification { 
    NSManagedObjectContext *managedObjectContext = [notification object]; 
    if (([managedObjectContext persistentStoreCoordinator] == self.persistentStoreCoordinator) && 
     (managedObjectContext != self.fetchedResultsControllerManagedObjectContext)) { 
     NSLog(@"managedObjectContextDidSave: %@", notification); 
     [self.fetchedResultsControllerManagedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
    } 
} 

- (void)managedObjectContext2ObjectsDidChange:(NSNotification *)notification { 
    NSLog(@"managedObjectContext2ObjectsDidChange: %@", notification); 
} 

@end 

@implementation HJBFoo 

@dynamic name; 
@dynamic show; 

@end 
+0

+ 1 आपके प्रश्न के लिए। मुझे यहां बताए गए समान समस्याएं हैं http://stackoverflow.com/questions/13527133/needed-clarifications-for-nsfetchedresultscontroller-and-nsfetchedresultscontrol। इसके अलावा, एक रडार भेजने के लिए धन्यवाद। –

+0

क्या समस्या तब बनी रहती है जब आप चरण 1 में स्थापित उसी संदर्भ के साथ प्राप्त नियंत्रक सेट अप करते हैं? –

+0

क्या आप 'manageObjectContextDidSave' विधि में अधिसूचना लॉग करते समय विशिष्ट परिवर्तन ('NO' से' YES' तक) देख सकते हैं? –

उत्तर

17

मुझे ऐसा लगता है कि NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext से ठीक/वैकल्पिक हल को लागू करने के अपने समस्या का हल भी है। आपका managedObjectContextDidSave विधि तो इस प्रकार दिखाई देगा:

- (void)managedObjectContextDidSave:(NSNotification *)notification { 
    NSManagedObjectContext *managedObjectContext = [notification object]; 
    if (([managedObjectContext persistentStoreCoordinator] == self.persistentStoreCoordinator) && 
     (managedObjectContext != self.fetchedResultsControllerManagedObjectContext)) { 
     NSLog(@"managedObjectContextDidSave: %@", notification); 

     // Fix/workaround from https://stackoverflow.com/questions/3923826/nsfetchedresultscontroller-with-predicate-ignores-changes-merged-from-different/3927811#3927811 
     for(NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) { 
      [[self.fetchedResultsControllerManagedObjectContext objectWithID:[object objectID]] willAccessValueForKey:nil]; 
     } 

     [self.fetchedResultsControllerManagedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
    } 
} 

और NSLog उत्पादन की उम्मीद के रूप में दिखता है:

Initial: (
    "<HJBFoo: 0xaa19670> (entity: HJBFoo; id: 0xaa1afd0 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p2> ; data: {\n name = 1;\n show = 1;\n})", 
    "<HJBFoo: 0xaa1a200> (entity: HJBFoo; id: 0xaa1af50 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p1> ; data: {\n name = 2;\n show = 0;\n})" 
) 
Initial fetchedObjects: (
    "<HJBFoo: 0x74613f0> (entity: HJBFoo; id: 0xaa1afd0 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p2> ; data: <fault>)" 
) 
managedObjectContextDidSave: NSConcreteNotification 0xaa1f480 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0xaa1ed90>; userInfo = { 
    inserted = "{(\n)}"; 
    updated = "{(\n <HJBFoo: 0xaa1f2d0> (entity: HJBFoo; id: 0xaa1af50 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p1> ; data: {\n name = 2;\n show = 1;\n})\n)}"; 
}} 
Save succeeded. Expected (in order) managedObjectContextDidSave, controllerDidChangeContent, managedObjectContext2ObjectsDidChange 
controllerDidChangeContent: (
    "<HJBFoo: 0x74613f0> (entity: HJBFoo; id: 0xaa1afd0 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p2> ; data: {\n name = 1;\n show = 1;\n})", 
    "<HJBFoo: 0xaa1f9c0> (entity: HJBFoo; id: 0xaa1af50 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p1> ; data: {\n name = 2;\n show = 1;\n})" 
) 
managedObjectContext2ObjectsDidChange: NSConcreteNotification 0xaa1fbb0 {name = NSObjectsChangedInManagingContextNotification; object = <NSManagedObjectContext: 0x745fa50>; userInfo = { 
    managedObjectContext = "<NSManagedObjectContext: 0x745fa50>"; 
    refreshed = "{(\n <HJBFoo: 0xaa1f9c0> (entity: HJBFoo; id: 0xaa1af50 <x-coredata://07E97098-E32D-45F6-9AB4-F9DAB9B0AC1A/HJBFoo/p1> ; data: {\n name = 2;\n show = 1;\n})\n)}"; 
}} 

तो निम्नलिखित बातें होती हैं:

  • परिवर्तन "पृष्ठभूमि में बना रहे हैं "संदर्भ managedObjectContext3 और सहेजा गया।
  • आपको NSManagedObjectContextDidSaveNotification और managedObjectContextDidSave: कहा जाता है। इस अधिसूचना में ऑब्जेक्ट शामिल है जिसे पृष्ठभूमि संदर्भ में अद्यतन किया गया था।
  • , कॉलिंग

    [self.fetchedResultsControllerManagedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
    

    अब कुछ भी ऐसा नहीं करेंगे क्योंकि अद्यतन वस्तु fetchedResultsControllerManagedObjectContext में लोड किया गया है या एक गलती है। विशेष रूप से, यह संदर्भ NSManagedObjectContextObjectsDidChangeNotification पोस्ट नहीं करेगा और प्राप्त परिणाम नियंत्रक अपडेट नहीं होंगे।

  • लेकिन अद्यतन वस्तुओं के लिए willAccessValueForKey पर कॉल करने से पहले इन वस्तुओं को लोड करने और गलती को आग लगाने के लिए fetchedResultsControllerManagedObjectContext पर बल दिया जाता है।
  • [self.fetchedResultsControllerManagedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
    
    उसके बाद

    कॉलिंग वास्तव में fetchedResultsControllerManagedObjectContext में वस्तुओं अद्यतन करता है।

  • इसलिए NSManagedObjectContextObjectsDidChangeNotification पोस्ट किया गया है और प्राप्त परिणाम नियंत्रक संबंधित प्रतिनिधि कार्यों को कॉल करता है।
+0

मार्टिन, आपके उत्तर के लिए +1। इसलिए, मुझे लगता है कि यह स्मृति-केवल ट्रैकिंग विकल्प के कारण है जैसा कि मैंने अपने पिछले प्रश्न में http://stackoverflow.com/questions/13527133/needed-clarifications-for-nsfetchedresultscontroller-and-nsfetchedresultscontrol पर समझाया है। तुम क्या सोचते हो? –

+1

@ फ्लेक्सडिक्टेड: मुझे SQLite स्टोर के साथ एक ही समस्या थी, लेकिन मैंने यह जांच नहीं की है कि यह फिक्स वहां भी मदद करता है। मैं इसे आज नहीं देख सकता, लेकिन आपको अद्यतित रखूंगा। –

+0

मार्टिन, आपके उत्तर के लिए धन्यवाद। आपका दिन शुभ हो। –

संबंधित मुद्दे