2013-01-13 1 views
0

논리적으로 발생하지 않기 때문에 처리 방법을 이해할 수 없다는 문제가 있습니다.SEGV_ACCERR 및 충돌 응용 프로그램이 언젠가 NSOperation에 충돌 할 때 [self.managedObjectContext save : & error]

나는 동시에 실행되는 NSOperation을 가지고 있습니다. 예를 들어,

- (void)main 
{ 
    @autoreleasepool 
    {   
     AppDelegate *appController = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 

     self.managedObjectContext = [[NSManagedObjectContext alloc] init]; 
     [self.managedObjectContext setUndoManager:nil]; 
     [self.managedObjectContext setPersistentStoreCoordinator: [appController persistentStoreCoordinator]]; 

     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
     [nc addObserver:self 
       selector:@selector(mergeChanges:) 
        name:NSManagedObjectContextDidSaveNotification 
       object:self.managedObjectContext]; 
     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
     NSEntityDescription *entity = [NSEntityDescription 
             entityForName:@"Entity" inManagedObjectContext:self.managedObjectContext]; 
     [fetchRequest setEntity:entity]; 

     [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K != %@",@"number1",[NSNumber numberWithInt:2]]]; 

     NSError *error; 
     NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

     for (NSManagedObject *obj in fetchedObjects) { 

      //Do Something with managed object then save   
      NSError *error = nil; 
      //[episode release]; 
      if (![self.managedObjectContext save:&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. If it is not possible to recover from the error, display an alert 
       // panel that instructs the user to quit the application by pressing the Home button. 
       // 
       NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
       abort(); 
      } 
     } 
    } 
} 

- (void)mergeChanges:(NSNotification *)notification 
{ 
    AppDelegate *appController = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
    NSManagedObjectContext *mainContext = [appController managedObjectContext]; 

    // Merge changes into the main context on the main thread 
    [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
           withObject:notification 
          waitUntilDone:YES]; 
} 

이없이 설명 응용 프로그램 충돌로 언젠가 동시에 작동하고 핵심 데이터에 내 개체를 업데이트하고, 그, 내 전형적인 NSOperation 내가이 라인에 해당 오류가 나타날 수

if (![self.managedObjectContext save:&error]) 

내 오류 보고서에서 내 질문에 앱 크래시를 방지하고 오류를 수정하는 방법이 있습니까? save을 수행 할 때 @syncronized을 사용할 수 있습니까? 이것은 다른 스레드와 다른 객체들 때문입니까? 이 문제를 어떻게 해결할 수 있습니까?

답변

2

응용 프로그램 대리인의 변경 내용을 병합하는 데 사용하는 코드를 이동하십시오.

따라서 application:didFinishLaunchingWithOptions:에 등록하십시오.

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
[nc addObserver:self 
     selector:@selector(mergeChanges:) 
      name:NSManagedObjectContextDidSaveNotification 
     object:nil]; // set nil here 

그리고, 항상 애플 대리자 내에서 mergesChanges: 방법을 만들 수 있습니다. 여기서는 통지가 주 스레드에서 실행되고 통지를 수신 한 컨텍스트가 주 스레드와 다르다는 것을 확인해야합니다.

- (void)mergeChanges:(NSNotification *)notification 
{ 
    if ([notification object] == [self managedObjectContext]) 
     return; 

    if (![NSThread isMainThread]) { 
     [self performSelectorOnMainThread:@selector(mergeChanges:) withObject:notification waitUntilDone:YES]; 
     return; 
    } 

    NSManagedObjectContext *mainContext = [self managedObjectContext]; 

    // Merge changes into the main context on the main thread 
    [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
           withObject:notification 
          waitUntilDone:YES]; 
} 

P. 여기에서 비 동시성 NSOperation을 사용하고 있는데, NSOperationQueue에 삽입하면 동시 방식으로 실행됩니다 (큐는 GCD를 통해이를 관리합니다).

+0

답장을 보내 주셔서 감사합니다. 그래서 저는 조엘처럼 슬픈 내 nsoperation을 변경할 필요가 없습니까? 내가했던 것처럼 main 메서드가 아닌 start 메서드를 재정의 하시겠습니까? – Piero

+0

'NSOperationQueue'를 사용하면 필요 없습니다. @Piero는 [가져 오기 및 표시하는 대용량 데이터 세트 - 코어 데이터] (http://www.cimgf.com/2011/08/22/importing-and-displaying-large)도 살펴 봅니다. - 데이터 - 세트 - 코어 - 데이터 /). 이 경우에는 동시 작업 ('start' 메서드를 재정 의하여 구현)을 사용하는 것이 유용하지 않습니다. –

+0

@ 피에로 당신에게 효과가 있습니까? –

1

이것은 동시 작업이 아닙니다. 그리고 메인 메서드가 끝나자 마자 처리가 해제 될 것이기 때문에 mergeChanges 통지는 결코 호출되지 않을 것입니다. 이것은 아마 NSManagedObjectContextDidSaveNotification 셀렉터가 실행되기 전에 발생합니다.

작업을 완료 할 때까지 계속되는 동시 작업을 원하면 start 메서드와 isConcurrent 메서드를 재정의해야합니다. 완료하기 전에 NSError 또는 선택자가 범위를 벗어 났으므로이 오류가 발생했을 수 있습니다. 이 기사를 읽으면 동시 작업과 비 동시 작업의 작동 방식을 이해할 수 있습니다.

자세한 내용은 Dave Dribin이 Concurrent Operations Demystified을 확인하십시오.

+0

응답 해 주셔서 감사 드리며이 통지에 등록해야 [addObserver NC : 자기 선택기 : @ 선택기 (mergeChanges :) 이름 : NSManagedObjectContextDidSaveNotification 개체 : self.managedObjectContext]; 이 방법을 삽입하면 더 이상 필요하지 않습니까? – Piero

+0

여기서 동시 작업을 만들 필요가 없습니다. 나는 @ 피에로가 대기열에 추가 된 작업을 사용한다고 생각합니다. –

+0

대기열은 스레드에서 스레드를 관리합니다. –

관련 문제