CoreData SQLite存储图像数据失败

时间:2014-03-13 10:56:23

标签: objective-c sqlite core-data ios7 blob

我已经将图像(JPEG)存储在CoreData(SQLite存储区)中一段时间​​没有问题。我最近不得不从外部源导入一些数据,它似乎与新数据一起正常工作。我刚遇到以下情况的数据实例: 1.实体加载正常并具有相关信息 2.恢复实体关系 3.包含NSData属性的实体为该属性返回nil 4.当我查询该对象的后备存储时,它具有显示在等效列

中的二进制数据

当我进一步查看商店时,似乎问题行只有38字节的信息存储在二进制数据列中。始终有30%的处理图像存储了这38个字节的数据,而其余图像则存储了完全准确和正确的数据。

导入过程在后台线程中运行。为了管理4.5Gb图像数据的内存需求,我以100-1000的批量运行导入(最初是1000但是已经尝试了100以查看是否存在差异)。我在批处理开始时创建一个nsmanagedobjectcontext,处理批处理然后保存上下文。在处理过程中,我将NSLog分配给相关对象的NSData属性的数据长度,并且它们在100%的时间内都是准确的。但是,当保存数据并且我在商店中查看时,30%只有38个字节的数据。我还尝试在创建每个对象后保存上下文但具有相同的30%dud结果。

我强烈感觉有一个多线程的元素搞砸了我的导入过程,但我无法在网上找到任何关于此的内容。会喜欢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方法是实际设置数据的地方

-(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];
}

所以这个代码在70%的情况下起作用,但在30%的情况下失败了......还有很多其他的东西在这周围发生,但处理图像的代码已经坚固了至少6个月拥有500个用户的字段,因此它与我在大规模对象后台线程进程中使用它的事实无关。

1 个答案:

答案 0 :(得分:-1)

叹息......事实证明CoreData决定存储文件&gt;现在130Kb作为外部数据。我在商店中看到的38个字节是与外部文件相关的Guid。现在我需要弄清楚当有明显数据时,为什么有效数据在我的应用主体中以nil的形式返回。

编辑: 好的,也解决了丢失的数据问题。我需要在模拟器上运行导入以最大化可用RAM。然后我将数据库(减去外部数据文件夹,因为我没有意识到它在那里)转移到iPad进行测试......当应用程序加载数据时,它试图检索外部数据文件但是不能找到它,所以将data属性加载为nil。没有任何例外或错误表明这种情况至少可以令人沮丧。