2010-08-10 9 views
117

मैं अब घंटों के लिए समस्या पर फंस गया हूं और स्टैक ओवरफ्लो पर इस बारे में सबकुछ पढ़ रहा हूं (और हर सलाह को लागू करता हूं), अब मुझे आधिकारिक तौर पर मदद की ज़रूरत है। ; ओ)"निष्पादित होने पर संग्रह को उत्परिवर्तित किया गया था" निष्पादित करें FetchRequest

यहाँ संदर्भ है:

अपने iPhone परियोजना में, मैं पृष्ठभूमि पर डेटा आयात और एक प्रबंधित वस्तु के संदर्भ में डालने की जरूरत है।

  • सहेजें मुख्य MOC
  • मुख्य MOC
  • द्वारा प्रयोग किया जाता लगातार दुकान समन्वयक के साथ एक पृष्ठभूमि MOC इन्स्तांत एक पर्यवेक्षक के रूप में मेरे नियंत्रक रजिस्टर: निम्न सलाह यहां पाया, यहाँ मैं क्या कर रहा है पृष्ठभूमि MOC
  • कॉल एक पृष्ठभूमि धागा
  • पर आयात विधि हर बार डेटा एकत्र हो सके के लिए NSManagedObjectContextDidSaveNotification अधिसूचना की, पृष्ठभूमि MOC पर डालें
  • एक बार सभी डेटा आयात किया गया है, पृष्ठभूमि MOC
  • बचाने अधिसूचना
  • रीसेट के लिए एक पर्यवेक्षक के रूप में मुख्य MOC में परिवर्तन मर्ज मेरी नियंत्रक अपंजीकृत मुख्य थ्रेड
  • पर, और पृष्ठभूमि MOC जारी
कभी कभी

(और बेतरतीब ढंग से), अपवाद ...

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x5e0b930> was mutated while being enumerated... 

... फेंक दिया जाता है जब मैं पृष्ठभूमि MOC पर executeFetchRequest कहते हैं, अगर आयात किए गए डेटा ALR जाँच करने के लिए डेटाबेस में eady मौजूद है। मुझे आश्चर्य है कि सेट को म्यूटेट कर रहा है क्योंकि आयात विधि के बाहर कोई भी चीज नहीं है।

मैं अपने नियंत्रक के पूरे कोड को शामिल किया है और अपने परीक्षण इकाई (अपने प्रोजेक्ट इन दो वर्गों और एप्लिकेशन प्रतिनिधि, जो असंशोधित किया गया है से मिलकर):

// 
// RootViewController.h 
// FK1 
// 
// Created by Eric on 09/08/10. 
// Copyright (c) 2010 __MyCompanyName__. All rights reserved. 
// 


#import <CoreData/CoreData.h> 

@interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> { 
    NSManagedObjectContext *managedObjectContext; 
    NSManagedObjectContext *backgroundMOC; 
} 


@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; 
@property (nonatomic, retain) NSManagedObjectContext *backgroundMOC; 

@end 


// 
// RootViewController.m 
// FK1 
// 
// Created by Eric on 09/08/10. 
// Copyright (c) 2010 __MyCompanyName__. All rights reserved. 
// 


#import "RootViewController.h" 
#import "FK1Message.h" 

@implementation RootViewController 

@synthesize managedObjectContext; 
@synthesize backgroundMOC; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.navigationController.toolbarHidden = NO; 

    UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshAction:)]; 

    self.toolbarItems = [NSArray arrayWithObject:refreshButton]; 
} 

#pragma mark - 
#pragma mark ACTIONS 

- (void)refreshAction:(id)sender { 
    // If there already is an import running, we do nothing 

    if (self.backgroundMOC != nil) { 
     return; 
    } 

    // We save the main moc 

    NSError *error = nil; 

    if (![self.managedObjectContext save:&error]) { 
     NSLog(@"error = %@", error); 

     abort(); 
    } 

    // We instantiate the background moc 

    self.backgroundMOC = [[[NSManagedObjectContext alloc] init] autorelease]; 

    [self.backgroundMOC setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]]; 

    // We call the fetch method in the background thread 

    [self performSelectorInBackground:@selector(_importData) withObject:nil]; 
} 

- (void)_importData { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundMOCDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundMOC];   

    FK1Message *message = nil; 

    NSFetchRequest *fetchRequest = nil; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"FK1Message" inManagedObjectContext:self.backgroundMOC]; 
    NSPredicate *predicate = nil; 
    NSArray *results = nil; 

    // fake import to keep this sample simple 

    for (NSInteger index = 0; index < 20; index++) { 
     predicate = [NSPredicate predicateWithFormat:@"msgId == %@", [NSString stringWithFormat:@"%d", index]]; 

     fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; 

     [fetchRequest setEntity:entity]; 
     [fetchRequest setPredicate:predicate]; 

     // The following line sometimes randomly throw the exception : 
     // *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x5b71a00> was mutated while being enumerated. 

     results = [self.backgroundMOC executeFetchRequest:fetchRequest error:NULL]; 

     // If the message already exist, we retrieve it from the database 
     // If it doesn't, we insert a new message in the database 

     if ([results count] > 0) { 
      message = [results objectAtIndex:0]; 
     } 
     else { 
      message = [NSEntityDescription insertNewObjectForEntityForName:@"FK1Message" inManagedObjectContext:self.backgroundMOC]; 
      message.msgId = [NSString stringWithFormat:@"%d", index]; 
     } 

     // We update the message 

     message.updateDate = [NSDate date]; 
    } 

    // We save the background moc which trigger the backgroundMOCDidSave: method 

    [self.backgroundMOC save:NULL]; 

    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.backgroundMOC]; 

    [self.backgroundMOC reset]; self.backgroundMOC = nil; 

    [pool drain]; 
} 

- (void)backgroundMOCDidSave:(NSNotification*)notification {  
    if (![NSThread isMainThread]) { 
     [self performSelectorOnMainThread:@selector(backgroundMOCDidSave:) withObject:notification waitUntilDone:YES]; 
     return; 
    } 

    // We merge the background moc changes in the main moc 

    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 
} 

@end 

// 
// FK1Message.h 
// FK1 
// 
// Created by Eric on 09/08/10. 
// Copyright 2010 __MyCompanyName__. All rights reserved. 
// 

#import <CoreData/CoreData.h> 

@interface FK1Message : NSManagedObject 
{ 
} 

@property (nonatomic, retain) NSString * msgId; 
@property (nonatomic, retain) NSDate * updateDate; 

@end 

// 
// FK1Message.m 
// FK1 
// 
// Created by Eric on 09/08/10. 
// Copyright 2010 __MyCompanyName__. All rights reserved. 
// 

#import "FK1Message.h" 

@implementation FK1Message 

#pragma mark - 
#pragma mark PROPERTIES 

@dynamic msgId; 
@dynamic updateDate; 

@end 

यह सब है! पूरी परियोजना यहां है। कोई तालिका दृश्य नहीं, कोई NSFetchedResultsController नहीं, पृष्ठभूमि थ्रेड से डेटा आयात करने वाले पृष्ठभूमि थ्रेड से कुछ और नहीं।

इस मामले में सेट को म्यूटेट कर सकता है?

मुझे पूरा यकीन है कि मुझे कुछ स्पष्ट याद आ रहा है और यह मुझे पागल कर रहा है।

संपादित करें:

यहाँ पूर्ण स्टैक ट्रेस है:

2010-08-10 10:29:11.258 FK1[51419:1b6b] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x5d075b0> was mutated while being enumerated.<CFBasicHash 0x5d075b0 [0x25c6380]>{type = mutable set, count = 0, 
entries => 
} 
' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x0255d919 __exceptionPreprocess + 185 
    1 libobjc.A.dylib      0x026ab5de objc_exception_throw + 47 
    2 CoreFoundation      0x0255d3d9 __NSFastEnumerationMutationHandler + 377 
    3 CoreData       0x02287702 -[NSManagedObjectContext executeFetchRequest:error:] + 4706 
    4 FK1         0x00002b1b -[RootViewController _fetchData] + 593 
    5 Foundation       0x01d662a8 -[NSThread main] + 81 
    6 Foundation       0x01d66234 __NSThread__main__ + 1387 
    7 libSystem.B.dylib     0x9587681d _pthread_start + 345 
    8 libSystem.B.dylib     0x958766a2 thread_start + 34 
) 
terminate called after throwing an instance of 'NSException' 
+1

एक्सकोड के रन मेनू में, "उद्देश्य-सी अपवादों पर रोकें" चालू करें, फिर अपने ऐप को डीबगर के नीचे चलाएं। तुम्हें क्या मिलता है? –

+1

यह पुष्टि करता है कि "executeFetchRequest: error:" पंक्ति पर ऐप क्रैश। मैंने अपने मूल प्रश्न में पूर्ण स्टैक ट्रेस जोड़ा है ... –

+0

और अन्य धागे के बारे में क्या? –

उत्तर

175

ठीक है, मुझे लगता है कि मैं मेरी समस्या हल है और मैं फ्रेड मैककैन के इस ब्लॉग पोस्ट धन्यवाद करना होगा:

http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

समस्या इस तथ्य से आती है कि मैं पृष्ठभूमि थ्रेड के बजाय मुख्य थ्रेड पर अपने पृष्ठभूमि moc को तुरंत चालू करता हूं। जब ऐप्पल बताता है कि प्रत्येक धागे को अपना स्वयं का मुखौटा होना चाहिए, तो आपको इसे गंभीरता से लेना होगा: प्रत्येक मॉक को थ्रेड में तत्काल होना चाहिए जो इसका उपयोग करेगा!

निम्नलिखित लाइनों जा रहा है ...

// We instantiate the background moc 

self.backgroundMOC = [[[NSManagedObjectContext alloc] init] autorelease]; 

[self.backgroundMOC setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]]; 

... _importData विधि में (बस से पहले अधिसूचना के लिए पर्यवेक्षक के रूप में रजिस्टर करने के लिए नियंत्रक) समस्या का हल।

आपकी मदद के लिए धन्यवाद, पीटर। और फ्रेड मैककन के मूल्यवान ब्लॉग पोस्ट के लिए धन्यवाद!

+2

ठीक है, बहुत सारे परीक्षण के बाद, मैं पुष्टि कर सकता हूं कि यह मेरी समस्या को हल करता है। जैसे ही मुझे अनुमति है, मैं इसे स्वीकार किए गए उत्तर के रूप में चिह्नित करूंगा ... –

+0

इस समाधान के लिए धन्यवाद! मर्ज के दौरान विवादों से बचने के लिए इस थ्रेड में लॉक/अनलॉक संदर्भ का बहुत अच्छा कार्यान्वयन है: http://stackoverflow.com/questions/2009399/cryptic-error-from-core-data-nsinvalidargumentexception-reason-referencedata64 – gonso

+4

+1 धन्यवाद प्रश्न, समाधान और फ्रेड मैककन के ब्लॉग पोस्ट को लिंक प्रदान करने के लिए बहुत कुछ .. इससे मुझे बहुत मदद मिली !!! – learner2010

0

मैं तालिका & रिकॉर्डव्यू में रिकॉर्ड के रिकॉर्ड के आयात पर काम कर रहा था। जब मैंने पृष्ठभूमि पर रिकॉर्ड सहेजने की कोशिश की तो

[self performSelectorInBackground:@selector(saveObjectContextInDataBaseWithContext:) withObject:privateQueueContext]; 

जैसे मैंने पहले से ही एक निजी QueueContext बनाया है। बस के साथ नीचे एक

[self saveObjectContextInDataBaseWithContext:privateQueueContext]; 

वास्तव में यह मेरी मूर्खता काम था पृष्ठभूमि धागे पर बचाने के लिए है, जबकि मैं पहले से ही रिकॉर्ड को बचाने के लिए एक privateQueueConcurrencyType बनाई कोड ऊपर की जगह।

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

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