Я пытаюсь загрузить изображения асинхронно и хранить их в Core Data. Шаг первый - загрузить json-файл, проанализировать его и сохранить объект в Core Data для каждого объекта в фиде. Эта часть работает нормально.Блокировка основных данных при загрузке изображений в фоновом потоке
Скажем, в итоге я получил 10 объектов Bird в Core Data. Каждая птица имеет имя, описание и т. Д. И отношение «многие» с BirdImage, которое является его собственной сущностью. BirdImage имеет атрибут «image_url» (строка) и атрибут «изображение» (Transformable).
Теперь, когда я добираюсь до экрана в приложении, в котором будут отображаться фотографии птиц, я сначала проверяю атрибут «изображение» BirdImage. Если это не null, я просто устанавливаю anyBirdEntity.image как образ UIImageView. Если он равен нулю, мне нужно загрузить изображение. В коде, который выглядит следующим образом:
@property (nonatomic, strong) AssetRequest *assetRequest; //this is just a wrapper for an asset url, cache policy, and time out
@property (nonatomic, strong) NSURLRequest *assetURLRequest;
@property (nonatomic, strong) NSURLConnection *assetConnection;
@property (nonatomic, strong) NSMutableData *assetConnectionData;
@property (nonatomic, strong) BirdImage *imageEntity;
@property (nonatomic, strong) NSManagedObjectContext *objectContext;
...
- (void)load {
dispatch_async(dispatchQueue, ^{
//Check for the image in Core Data
self.objectContext = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.objectContext.parentContext = [[CoreDataController sharedController] managedObjectContext];
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"BirdImage"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"image_url = %@", [self.assetRequest.assetURL absoluteString]];
[fetch setPredicate:predicate];
NSArray *objects = [self.objectContext executeFetchRequest:fetch error:nil];
if ([objects count] > 0)
{
BirdImage *birdImage = [objects objectAtIndex:0];
if (birdImage.image) {
dispatch_async(dispatch_get_main_queue(), ^{
BirdAsset *asset = [[BirdAsset alloc] init];
asset.url = [NSURL URLWithString:birdImage.image_url];
asset.image = birdImage.image;
if (self.successBlock)
self.successBlock(asset); //the caller will use asset.image for the UIImageView
});
return;
}else{
//no image found, need to download it
self.imageEntity = birdImage; //this is the entity I want to re-save in Core Data once the image finishes downloading
dispatch_async(dispatch_get_main_queue(), ^{
self.assetURLRequest = [NSURLRequest requestWithURL:self.assetRequest.assetURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:self.assetRequest.timeOut];
self.assetConnection = [[NSURLConnection alloc] initWithRequest:self.assetURLRequest delegate:self startImmediately:NO];
[self.assetConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.assetConnection start];
});
}
}
}];
});
}
Затем, когда загрузка завершается:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
dispatch_async(dispatchQueue, ^{
UIImage *resultImage = [UIImage decompressImageFromData:self.assetConnectionData];
NSData *resultData = UIImagePNGRepresentation(resultImage);
DLog(@"saving to core data: %@", self.imageEntity.image_url); //THIS HAPPENS 10 TIMES (every time)
self.imageEntity.image = resultImage;
@try {
NSError *saveError = nil;
if (![self.objectContext save:&saveError])
NSLog(@"saveError %@", saveError);
}
@catch (NSException *exception) {
NSLog(@"Exception: %@", exception);
}
[[CoreDataController sharedController] saveContext];
BirdAsset *finalAsset = [[BirdAsset alloc] init];
finalAsset.data = resultData;
finalAsset.image = resultImage;
finalAsset.url = [NSURL URLWithString:self.imageEntity.image_url];
DLog(@"SUCCESS"); //THIS HAPPENS anywhere from 4-7 times. I never get all 10 images.
dispatch_async(dispatch_get_main_queue(), ^{
if (self.successBlock)
self.successBlock(finalAsset);
});
});
}
Изображения загружая хорошо, и когда я осмотреть мою базу данных я могу видеть BLOB данные для каждого «изображения BirdImage ». Проблема состоит в том, что из 10 изображений на самом деле их отображает случайное число (где-то от 4 до 7 из них при первом запуске). Затем, если я снова вернусь на этот экран, приложение закроется, без сообщений об ошибках или сбоев. Я подозреваю, что это своего рода блокировка Core Data.
Я знаю, что должен «получить доступ к контексту из того же потока, который его создал». Но если я получаю доступ к контексту в разных методах (например, в методах load и connectionDidFinishLoading выше), как я могу использовать один и тот же поток? Другими словами, как я могу изменить свой код, чтобы я выполнял потокобезопасное сохранение контекста CoreData изображений, когда они заканчивают загрузку?
При загрузке этих изображений вы используете один и тот же объект для каждой загрузки или один объект для загрузки? –
[Помогает?] (Http://stackoverflow.com/questions/11183456/core-data-multiple-threads-view-controller-not-updating). – HAS
Основные данные не выбрасывают 'NSException'. Вы не должны обертывать вызовы сохранения в try/catch, как это, поскольку это может скрывать/маскировать ошибки в других частях вашего кода. –