我已经将图像(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个用户的字段,因此它与我在大规模对象后台线程进程中使用它的事实无关。
答案 0 :(得分:-1)
叹息......事实证明CoreData决定存储文件&gt;现在130Kb作为外部数据。我在商店中看到的38个字节是与外部文件相关的Guid。现在我需要弄清楚当有明显数据时,为什么有效数据在我的应用主体中以nil的形式返回。
编辑: 好的,也解决了丢失的数据问题。我需要在模拟器上运行导入以最大化可用RAM。然后我将数据库(减去外部数据文件夹,因为我没有意识到它在那里)转移到iPad进行测试......当应用程序加载数据时,它试图检索外部数据文件但是不能找到它,所以将data属性加载为nil。没有任何例外或错误表明这种情况至少可以令人沮丧。