0

백그라운드 스레드를 사용하여 UIManagedDocument/Core Data의 데이터를 업데이트하는 중 일부 문제가 있습니다. 특히 NSFetchResultsController을 사용하여 배경 스레드의 지오 코딩 된 데이터를 기반으로지도 주석을 업데이트합니다 (주 MOC로 다시 병합 한 후). UIManagedDocument이 해당 점포 및/또는 해당 점포로 데이터를 커밋하기 때문에지도가 업데이트되지 않습니다. 여러 MOC (부모 및 자식). 앱을 닫고 다시 열면 주석이 채워지므로 영구 저장소에 대한 커밋이 어느 시점에 발생하지만이 커밋을 강제로 수행하는 방법이 명확하지 않아 NSFetchResultsController을 업데이트합니다.코어 데이터 : NSManagedObjectContext, NSFetchResultsController 및 UIManagedDocument

상무부 업데이트 배경 스레드 : (내 애플 대리자에서) 그 호출되는 저장하면

- (void) populateGPSCoordsInClubsInContext: (NSManagedObjectContext *) mainCtx 
{    
    dispatch_queue_t MapFetchQ = dispatch_queue_create("Google Map Data Fetcher", NULL); 
    dispatch_async(MapFetchQ, ^{ 

     NSManagedObjectContext * ctxThread = [[NSManagedObjectContext alloc] init]; 
     [ctxThread setPersistentStoreCoordinator:mainCtx.persistentStoreCoordinator]; 


     NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"Club"]; 
     request.predicate = [NSPredicate predicateWithFormat:@"inRegion.name=%@", self.name]; 
     NSError *error = nil; 

     NSArray * clubs = [ctxThread executeFetchRequest:request error:&error]; 

     NSLog(@"[%@] Fetching map data. Club count is %d", self.name, [clubs count]); 

     int delayCounter = 0; 

     for(Club * club in clubs) 
     { 
      if(![club.hasCoord boolValue] && club != nil) 
      { 
       delayCounter++; // to deal with google maps api's DoS protection    

       [club setLongitudeAndLattitudeFromGoogle]; 
       NSError * error; 

       if(![ctx save:&error]) 
       NSLog(@"[%@] Problem saving region to database.", self.name); 

      } 

      if(delayCounter == 8) 
      {    
       [NSThread sleepForTimeInterval:(NSTimeInterval)2.0]; 
       delayCounter = 0; 
      } 
     } 
    }); 
    dispatch_release(MapFetchQ); 
} 

, 나는 주 스레드의 알림을 잡아 그렇게 같은 :

- (void) contextDidSave: (NSNotification *) notification 
{ 
    NSManagedObjectContext * ctx = [self.clubsDB managedObjectContext]; 
    [ctx mergeChangesFromContextDidSaveNotification:notification]; 

    NSArray * updates = [[notification.object updatedObjects] allObjects]; 

    for(Club * club in updates) // This never fires because updates never has objects 
    { 
     NSLog(@"*********** %@", club.name); 
    } 

    NSLog(@"[%@] %@", [self class], NSStringFromSelector(_cmd)); 

} 
여기에 몇 가지 코드는

-(void) setupFRC 
{ 

    NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"Club"]; 
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]; 
    request.predicate = [NSPredicate predicateWithFormat:@"inRegion.name=%@ AND hasCoord=%@",[self.clubsDB regionTitleAsString], [NSNumber numberWithBool:YES]]; // Follow the relationshop and only display clubs from THIS region. 

    //request.predicate = [NSPredicate predicateWithFormat:@"inRegion.name=%@",[self.clubsDB regionTitleAsString]]; 

    self.debug = YES; 

    self.fetchedResultsController = 
    [[NSFetchedResultsController alloc] initWithFetchRequest:request 
             managedObjectContext:self.clubsDB.managedObjectContext 
              sectionNameKeyPath:nil 
                cacheName:nil]; 
} 
0 :

내가 같은 내 가져온 결과 컨트롤러를 설정 한 (술어는 데이터 저장소에 커밋 한 후 응용 프로그램을 다시 부팅 예상대로 결과가 정확)

페치 된 결과 컨트롤러가 원하는대로 동작하도록 적절한 MOC를 업데이트하는 방법에 대한 아이디어가 있습니까?

+0

누구나? 완전히 갇혀 .. : / – Andrew

답변

0

UIManagedDocument가 커밋을 보내는 방식에 문제가 있습니다. 내가 생각할 수있는 유일한 해결책은 UIManagedDocument 사용을 중단하고 기본 Master-Detail 템플릿에 제공된대로 PersistentStore의 컨텍스트를 사용하는 것입니다.

편집 : 추가 연구 후 UIManagedDocument가 변경 사항을 적용하는 방법이없는 것처럼 보이므로 영구 저장소에서 생성 된 컨텍스트를 전달하는 것이 좋습니다. Apple이 아직 UIManagedDocument에 사용할 수있는 샘플 코드를 제공하지 않은 것은 우연이 아닙니다. 나는 기본 템플릿을 고수 할 것이다. 여기

비슷한 문제에 직면 사람에 대한 링크, 그리고 그들의 "솔루션"- 때로는 가장 좋은 방법은 하나가 아니라는 것을 알고하는 것입니다 : P에게

Core Data managed object does not see related objects until restart Simulator

0

을 내가 실제로 해결 할 수 있었다 발행물. 그 트릭은 컨텍스트가 FRC를 설정하기 전에 편집 중이던 객체로 미리 채워져 있는지 확인하는 것이 었습니다. 사실 UIManagedDocument가 예상대로 작동하지 않는다는 (또는 설명서에서도 설명하는 것처럼) 사실은 매우 혼란 스럽습니다. 당황 스럽습니다.

0

좋아요, 나는 코드를 편집하여 어떻게 보이는지 알려줄 것입니다. UIManagedDocument에서 populateGPSCoordsInClubsContext로 MOC를 전달한다고 가정합니다. 이다, 이런 식으로 그 일에 대한 멋진 것들을

// NOTE: Make it clear you expect to work on a document... 
- (void) populateGPSCoordsInClubsInContext: (UIManagedDocument *) document 
{    
    dispatch_queue_t MapFetchQ = dispatch_queue_create("Google Map Data Fetcher", NULL); 
    dispatch_async(MapFetchQ, ^{ 

     NSManagedObjectContext * ctxThread = [[NSManagedObjectContext alloc] init]; 
     // NOTE: Make changes up into the context of the document 
     ctxThread.parentContext = document.managedObjectContext;  

     NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"Club"]; 
     request.predicate = [NSPredicate predicateWithFormat:@"inRegion.name=%@", self.name]; 
     NSError *error = nil; 

     NSArray * clubs = [ctxThread executeFetchRequest:request error:&error]; 

     NSLog(@"[%@] Fetching map data. Club count is %d", self.name, [clubs count]); 

     int delayCounter = 0; 

     for(Club * club in clubs) 
     { 
      if(![club.hasCoord boolValue] && club != nil) 
      { 
       delayCounter++; // to deal with google maps api's DoS protection    

       [club setLongitudeAndLattitudeFromGoogle]; 
       NSError * error; 

       // NOTE: This notifies the parent context of the changes. 
       if(![ctx save:&error]) 
       NSLog(@"[%@] Problem saving region to database.", self.name); 
       // NOTE: However, since a UIManagedDocument is an "auto-save" 
       // document, we need to tell it that is is dirty... 
       [document updateChangeCount:UIDocumentChangeDone]; 
      } 

      if(delayCounter == 8) 
      {    
       [NSThread sleepForTimeInterval:(NSTimeInterval)2.0]; 
       delayCounter = 0; 
      } 
     } 
    }); 
    dispatch_release(MapFetchQ); 
} 

하나 ... 거기에 약간의 차이가 이미하고있는 일에 있지만 우리가 아는 한, 한 줄의 코드가 모든 차이를 만들 수 있습니다 (심지어 적어도 일관성을 위해) 알림을 처리 할 필요가 없다는 것을 의미합니다.

이 다른 방법으로 수행하려면을 원하면 다음을 수행 할 수 있습니다.

 ctxThread.parentContext = document.parentContext;  

그러면 문서에서 updateChangeCount를 호출하지 않을 것입니다. 이러한 변경 사항은 상위 컨텍스트 및 파일로 이동합니다. 그러나이 작업을 수행하면 알림을 처리 할 필요가 없습니다. 이후 페치가 자동으로 알림을 볼 수 있기 때문입니다. 물론 변경 사항을 새로 고치려면 알림을 처리 할 수는 있지만 그 모든 것. 인출시이를 확인하려면 다른 작업을 수행 할 필요가 없습니다.

UIManagedDocument는 대중적인 신념과는 달리 (일단 규칙을 알면) 매우 효과적이고 쉽습니다.

관련 문제