2014-03-13 2 views
0

문제없이 CoreData (SQLite store)에 이미지 (JPEG)를 저장했습니다. 최근에 외부 소스에서 일부 데이터를 가져와야했으며 새 데이터로 잘 작동하는 것으로 보입니다. 다음 내용이 적용되는 데이터 인스턴스를 발견했습니다. 1. 엔티티가 올바르게로드되고 관련 정보가 있습니다. 2. 엔티티 관계가 복원되었습니다. 3. NSData 속성이 포함 된 엔티티는 해당 속성에 대해 nil을 반환합니다. 4. 해당 개체에 대한 백업 저장소를 쿼리하면 해당 열에 이진 데이터가 표시됩니다.CoreData SQLite에 이미지 데이터 저장 실패

저장소를 조사한 결과 문제가되는 행에 38 바이트의 정보 만 저장되어있는 것처럼 보입니다 이진 데이터 열. 처리되는 모든 이미지의 일관되게 30 %는이 38 바이트의 데이터를 저장하고 나머지는 완전히 정확하고 정확한 데이터를 저장합니다.

가져 오기 프로세스가 백그라운드 스레드에서 실행됩니다. 4.5Gb 이미지 데이터의 메모리 요구 사항을 관리하기 위해 가져 오기를 100-1000 배치로 실행합니다 (처음에는 1000이지만 어떤 차이가 있는지 보려면 100을 시도했습니다). 배치 시작 부분에 nsmanagedobjectcontext를 작성한 다음 배치를 처리 한 다음 컨텍스트를 저장합니다. 처리하는 동안 NSLog는 문제의 객체의 NSData 속성에 할당되는 데이터의 길이이며 정확한 100 %의 시간입니다. 그러나 데이터가 저장되면 매장에서 30 %는 38 바이트의 데이터 만 갖습니다. 나는 또한 모든 객체가 생성 된 후에 컨텍스트를 저장하려고 시도했지만 동일한 30 %의 불량 결과가 발생했습니다.

나는 멀티 스레딩 요소가있어 가져 오기 프로세스가 엉망으로되어 버렸지 만 온라인에 대해서는 아무것도 찾을 수 없습니다. 도대체 내 데이터로 무슨 일이 일어나고 있는지에 대한 CoreData 전문가의 조언을 원합니다.

편집 : 코드의 부분 집합 (다른 물건을 많이 가져 오기 프로세스에서 진행이 있지만, 이미지 가져 오기가 합리적으로 선형)

NSArray *importLines = [[importFileContents componentsSeparatedByString:@"\r\n"] retain]; 

    int batch = 100; 
    int currentBatch = 0; 
    int totalLines = importLines.count; 

    while(currentBatch*batch<totalLines) 
    { 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 
     // Create a live context 
     NSManagedObjectContext *liveContext = [[PRModel sharedInstance] newLiveManagedObjectContext]; 
     NSMutableArray *errorMessages = [[NSMutableArray alloc]init]; 
     for(int i=currentBatch*batch; i<(currentBatch+1)*batch && i<totalLines; i++) 
     { 
      NSString *importLine = [importLines objectAtIndex:i]; 

      NSArray *importLineData = [importLine componentsSeparatedByString:@"~"]; 
      if([importLineData count]>0) 
      { 
       NSString *lineType = [importLineData objectAtIndex:0]; 
       int lineTypeID = [lineType intValue]; 
       NSString *errorMessage = nil; 
       switch(lineTypeID) 
       { 
        // other cases handle other object types and all work fine 
        case 5: 
         errorMessage = [DataImporter processPhoto:importLineData withRefDate:refDate intoContext:liveContext]; 
         // try saving every object to see if it makes an effect 
         [Utils saveManagedObjects:liveContext]; 
         break; 
        default: 
         break; 
       } 
       if(errorMessage!=nil) 
       { 
        [errorMessages addObject:errorMessage]; 
       } 
      } 
     } 
     [Utils saveManagedObjects:liveContext]; 
     [liveContext release]; 
     // Update the errors/missing areas/missing items files in case we get a memory crash 
     [DataImporter writeErrors:errorMessages]; 
     [errorMessages release]; 
     currentBatch++; 
     NSLog(@"Batch %d complete",currentBatch); 
     [pool release]; 
    } 

PRModel newLiveManagedObjectContext

-(NSManagedObjectContext*)newLiveManagedObjectContext 
{ 
    NSPersistentStoreCoordinator *coordinator = [self livePSC]; 
    NSManagedObjectContext *newContext = nil; 
    if (coordinator != nil) { 
     newContext = [[NSManagedObjectContext alloc] init]; 
     [newContext setPersistentStoreCoordinator: coordinator]; 
    } 
    return newContext; 
} 
- (NSPersistentStoreCoordinator *)livePSC { 

    if (livePSC != nil) { 
     return livePSC; 
    } 

    LiveDatabaseUpgradeController *upgrader = [[LiveDatabaseUpgradeController alloc]initWithDelegate:nil]; 
    @try{ 
     livePSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.currentModel]; 
     NSError *error = nil; 
     if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:[self currentModelStorePath]] options:nil error:&error]) 
     { 
      NSLog(@"Failed To Open Data Store. Error:%@, %@", error, [error userInfo]); 
      @throw [NSException exceptionWithName:@"Upgrade Required!" reason:@"attempted to open your database but failed. To quit press the home button." userInfo:nil]; 
     } 
    } 
    @catch(NSException *e){ 
     [Utils showAlert:[e name] withMessage:[e reason] withDelegate:nil]; 
    } 
    @finally{ 
     [upgrader release]; 
    } 
    return livePSC; 
} 

processPhoto 메서드

+(NSString*)processPhoto:(NSArray*)data withRefDate:(NSDate*)refDate intoContext:(NSManagedObjectContext*)liveContext// withData:(bool)saveData 
{ 
    if(data.count!=10) 
     return [NSString stringWithFormat:@"Expected 10 items, found %d",[data count]]; 
    NSString *partialPath = [data objectAtIndex:8]; 
    if([partialPath isEqualToString:@"NULL"]) 
     return nil; 
    NSString *filePath = [[[PRModel sharedInstance] applicationDocumentsDirectory] stringByAppendingPathComponent:partialPath]; 
    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath]) 
    { 
     return [NSString stringWithFormat:@"File not found for %@",filePath]; 
    } 
    // Got everything we need so create a photo 
    PhotoEntity *photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:liveContext]; 
    photo.photoID = [data objectAtIndex:9]; 
    photo.imageType = @"PHOTO"; 
    photo.photoDescription = @""; 
    UIImage *photoImage = [[UIImage alloc]initWithContentsOfFile:filePath]; 
    [photo setImage:photoImage inContext:liveContext]; 
    [photoImage release]; 
    return nil; 
} 

setImage 메서드는 데이터가 ac tually 다른 물건이 주위에 일어나고 있지만 처리 이미지의 코드는 적어도위한 견고한되었습니다의 전체 무리가있다 ... 그래서이 코드의 경우 70 %에서 작동하지만 30 %에 실패

-(void)setImage:(UIImage *)image inContext:(NSManagedObjectContext *)context 
{   
    if(self.photoData==nil) 
    { 
     // Create a new photo data entity 
     self.photoData = [NSEntityDescription insertNewObjectForEntityForName:@"PhotoData" inManagedObjectContext:context]; 
    } 
UIImage *resizedImage = [image copyImageResizedWithLength:MAX_STORE_RESOLUTION interpolationQuality:kCGInterpolationHigh]; 
    NSData *data = UIImageJPEGRepresentation(resizedImage, 0.6); 
    NSLog(@"ImageLength=%d",[data length]); 
    self.photoData.imageData = data; 
    [resizedImage release]; 
} 

설정 500 명의 사용자가있는 현장에서 6 개월이므로 대량 객체 백그라운드 스레드 프로세스에서 사용하고 있다는 사실과 분명히 관련이 있습니다.

+0

배경에서 가져 오는 방법, 특히 컨텍스트가 설정된 사람과 관계가 생성되는 방법을 보여 주어야합니다. 부가 메모 : 이미지는 CoreData에 직접 저장하지 않는 것이 좋습니다. – Volker

+0

> 500K 이상의 이미지는 외부에 저장해야하지만 크기 조정 및 압축의 요점은 이미지가 60K-120K 범위에 있는지 확인하는 것입니다. 응용 프로그램은 현장에서 3 년 동안 있었고 이미지 처리는 기본적으로 이와 같은 오류가 발생하지 않고 동일했습니다. 이 대용량 데이터 가져 오기 (42000 이미지) 이외에도 데이터베이스는 일반적으로 언제든지 1000-2000 개의 이미지 만 저장합니다. 오류 비율은 첫 번째 저장에서 시작된 것으로 보이므로 볼륨이 아니라고 생각합니다. –

+0

백그라운드 스레드의 관리되는 개체 컨텍스트가 방법으로 만들어 지므로 코드에서 사용할 수있는 코드가 명확하지 않습니다. 동시 설정. – Volker

답변

-1

한숨 ... CoreData가 외부 데이터로> 130KB의 파일을 저장하기로 결정한 것으로 나타났습니다. 저장소에서보고있는 38 바이트는 외부 파일과 관련된 Guid입니다. 이제 데이터가 명확하게 표시 될 때 유효한 데이터가 내 앱 본문에서 nil로 반환되는 이유를 알아야합니다.

편집 : 좋아, 누락 된 데이터 문제도 해결했습니다. 사용 가능한 RAM을 최대화하려면 시뮬레이터에서 가져 오기를 실행해야합니다. 그런 다음 테스트를 위해 iPad에 데이터베이스 (마이너스 외부 데이터 폴더 제외)를 전송했습니다 ... 앱이 데이터를로드하면 외부 데이터 파일을 검색하려고 시도했지만 찾을 수 없었습니다. 데이터 속성을 nil로로드했습니다. 예외 또는 오류가 없었 음을 나타내는 가장 실망스러운 사례였습니다.

+0

대답이 아닙니다. 대답이 아닌 답변을 게시하는 대신 질문을 편집하십시오;) 감사합니다! –