এক্সিকিউটেফ্যাচআরকুয়েস্টে "গণনা করার সময় সংগ্রহটি পরিবর্তন করা হয়েছিল"


121

আমি এখন কয়েক ঘন্টা ধরে আটকে আছি এবং স্ট্যাকওভারফ্লোতে এ সম্পর্কে সমস্ত কিছু পড়েছি (এবং প্রাপ্ত প্রতিটি পরামর্শ প্রয়োগ করুন), এখন আমি আনুষ্ঠানিকভাবে সাহায্যের প্রয়োজন in ; O)

এখানে প্রসঙ্গে:

আমার আইফোন প্রকল্পে, আমাকে ব্যাকগ্রাউন্ডে ডেটা আমদানি করতে হবে এবং এটি একটি পরিচালিত অবজেক্ট প্রসঙ্গে .োকাতে হবে। এখানে পাওয়া পরামর্শ অনুসরণ করে, আমি এখানে যা করছি তা এখানে:

  • মূল মোকটি সংরক্ষণ করুন
  • প্রধান এমওসি দ্বারা ব্যবহৃত ধ্রুবক স্টোর সমন্বয়কের সাথে একটি পটভূমি এমওকে ইনস্টল করুন
  • ব্যাকগ্রাউন্ড এমওকে জন্য NSManagedObjectContextDidSaveNotifications বিজ্ঞপ্তির পর্যবেক্ষক হিসাবে আমার নিয়ামক নিবন্ধন করুন
  • পটভূমির থ্রেডে আমদানি পদ্ধতিটি কল করুন
  • প্রতিবার ডেটা প্রাপ্ত হওয়ার পরে, এটি ব্যাকগ্রাউন্ড এমওকে sertোকান
  • সমস্ত ডেটা আমদানি হয়ে গেলে, ব্যাকগ্রাউন্ড এমওকে সংরক্ষণ করুন
  • মূল থ্রেডে পরিবর্তনগুলিকে মূল উপসাগরে মার্জ করুন
  • বিজ্ঞপ্তির পর্যবেক্ষক হিসাবে আমার নিয়ামকটিকে নিবন্ধভুক্ত করুন
  • ব্যাকগ্রাউন্ড এমওকে পুনরায় সেট করুন এবং ছেড়ে দিন

কখনও কখনও (এবং এলোমেলোভাবে), ব্যতিক্রম ...

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

... আমদানি করা ডেটাবেস ডেটাবেজে ইতিমধ্যে উপস্থিত রয়েছে কিনা তা পরীক্ষা করার জন্য, যখন আমি ব্যাকগ্রাউন্ড এমওকে এক্সিকিউটিফ্যাচআরকেস্ট কল করি তখন তা নিক্ষেপ করা হয়। আমি ভাবছি সেটটি কী রূপান্তরিত করছে যেহেতু আমদানি পদ্ধতির বাইরে চালানো কিছুই নেই।

আমি আমার নিয়ামক এবং আমার পরীক্ষার সত্তার পুরো কোডটি অন্তর্ভুক্ত করেছি (এই প্রকল্পে এই দুটি শ্রেণীর সমন্বয়ে গঠিত আমার প্রকল্প এবং অ্যাপটি প্রতিনিধি, যা সংশোধিত হয়েছে):

//
//  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

এটাই সব ! পুরো প্রকল্প এখানে। কোনও সারণী দর্শন নেই, কোনও এনএসফ্যাচড্রিজাল্টস কনট্রোলার নেই, একটি ব্যাকগ্রাউন্ড থ্রেড ছাড়া আর কিছুই নয় যা ব্যাকগ্রাউন্ড এমওকে ডেটা আমদানি করে।

এই ক্ষেত্রে সেটটি কী রূপান্তর করতে পারে?

আমি নিশ্চিত যে আমি স্পষ্ট কিছু মিস করছি এবং এটি আমাকে পাগল করছে।

সম্পাদনা করুন:

সম্পূর্ণ স্ট্যাক ট্রেস এখানে:

    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'

2
এক্সকোডের রান মেনুতে, "অবজেক্ট-সি ব্যতিক্রমগুলি বন্ধ করুন" চালু করুন, তারপরে ডিবাগারের অধীনে আপনার অ্যাপ্লিকেশনটি চালান। আপনি কি খুঁজে পান?
পিটার হোসি

1
এটি নিশ্চিত করে যে অ্যাপ্লিকেশনটি "executeFetchRequest: ত্রুটি:" লাইনে ক্রাশ করেছে। আমি আমার মূল প্রশ্নের সাথে পুরো স্ট্যাক ট্রেস যুক্ত করেছি ...
এরিক মরানড

এবং অন্যান্য থ্রেড সম্পর্কে কি?
পিটার হোসি

হুম, এখানে মূল থ্রেড স্ট্যাক হয়: # 0 0x958490fa মধ্যে mach_msg_trap mach_msg # # 1 0x95849867 __CFRunLoopServiceMachPort 2 0x0253f206 # __CFRunLoopRun 3 0x0249c8b4 # CFRunLoopRunSpecific 4 0x0249c280 # 5 CFRunLoopRunInMode মধ্যে 0x0249c1a1 6 নম্বর 0x027a82c8 GSEventRunModal # 7 0x027a838d GSEventRun # টি 8 0x00021b58 ইউআইএ অ্যাপ্লিকেশনমেন # 9 0x00001edc in main.m: 16 অন্যান্য 2 টি থ্রেড রয়েছে (লিবিডিসপ্যাচ-ম্যানেজার এবং "ওয়েবথ্রেড") তবে তারা আরও তথ্য দেয় না।
এরিক মরানড

উত্তর:


182

ঠিক আছে, আমি মনে করি আমি আমার সমস্যার সমাধান করেছি এবং ফ্রেড ম্যাকক্যান্সের এই ব্লগ পোস্টকে অবশ্যই ধন্যবাদ জানাতে হবে:

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

সমস্যাটি আসল বলে মনে হচ্ছে যে আমি ব্যাকগ্রাউন্ড থ্রেডের পরিবর্তে আমার ব্যাকগ্রাউন্ড ম্যাকটি মূল থ্রেডে ইনস্ট্যান্ট করি। অ্যাপল যখন বলে যে প্রতিটি থ্রেডের নিজস্ব এমওকে থাকা দরকার, আপনি এটি গুরুত্ব সহকারে নিতে হবে: প্রতিটি এমওকে অবশ্যই থ্রেডে ইনস্ট্যান্ট করা উচিত যা এটি ব্যবহার করবে!

নিম্নলিখিত লাইনগুলি সরানো হচ্ছে ...

// We instantiate the background moc

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

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

... _ম্পোর্টডাটা পদ্ধতিতে (বিজ্ঞপ্তির জন্য পর্যবেক্ষক হিসাবে নিয়ামককে নিবন্ধকরণের ঠিক আগে) সমস্যার সমাধান করে।

পিটার আপনার সাহায্যের জন্য ধন্যবাদ। এবং ফ্রেড ম্যাকক্যান্সকে এর মূল্যবান ব্লগ পোস্টের জন্য ধন্যবাদ!


2
ঠিক আছে, অনেক পরীক্ষার পরে, আমি নিশ্চিত করতে পারি যে এটি আমার সমস্যাটি একেবারে সমাধান করেছে। আমি অনুমতি পাওয়ার সাথে সাথে এটিকে স্বীকৃত উত্তর হিসাবে চিহ্নিত করব ...
এরিক মরানড

এই সমাধানের জন্য ধন্যবাদ! এই থ্রেড একটি খুব ভাল একত্রীকরণ সময় এড়ানোর দ্বন্দ্ব লক / আনলক প্রসঙ্গের বাস্তবায়ন হয়েছে stackoverflow.com/questions/2009399/...
gonso

4
+1 প্রশ্ন, সমাধান এবং ফ্রেড ম্যাকক্যানের ব্লগ পোস্টে লিঙ্ক সরবরাহ করার জন্য অনেক ধন্যবাদ .. এটি আমাকে অনেক সাহায্য করেছে !!!
লার্নার 2010

3
each moc must be instantiated in the thread that will be using itআমি যদিও কেবল এমওসি-তে অপারেশন একই থ্রেডে থাকা উচিত, তবে এমওসি নিজেই তৈরি করা উচিত, এটি যদি ব্যক্তিগত বেসরকারী এমওসি হয় তবে সম্পর্কিত সারিটি এখনও বিদ্যমান নেই ..
জ্যানোস

@ জানোস আমার এখানে একই প্রশ্ন রয়েছে। আপনি কীভাবে থ্রেডে প্রসঙ্গটি ব্যবহার করবেন তা ইনস্ট্যান্ট করতে পারেন? থ্রেডটি এখনও বিদ্যমান নেই। আমি সুইফট ব্যবহার করছি এবং আমি "_আইপোর্টডাটা পদ্ধতিতে চলমান" এর অর্থ কী তা বুঝতে পারি না।
টডনলে

0

আমি টেবিলভিউতে রেকর্ড এবং রেকর্ড প্রদর্শনের আমদানিতে কাজ করছিলাম। আমি নীচের মত পটভূমিতে রেকর্ড সংরক্ষণ করার চেষ্টা করার সময় একই সমস্যার মুখোমুখি হয়েছিল

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

আমি ইতিমধ্যে একটি প্রাইভেটকিউ কনটেক্সট তৈরি করার সময়। উপরের কোডটি কেবল নীচের একের সাথে প্রতিস্থাপন করুন

[self saveObjectContextInDataBaseWithContext:privateQueueContext];

আমি ইতিমধ্যে রেকর্ড সংরক্ষণের জন্য একটি প্রাইভেটকিউউনকুরান্টিটাইপ তৈরি করার সময় পটভূমির থ্রেডে সংরক্ষণ করা আমার বোকামি কাজ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.