Я пытаюсь выполнить операцию Core-data в фоновом контексте. Я вставляю все свои данные в фоновый контекст, но когда я извлекаю в основном потоке, он не показывает никаких данных, которые я уже вставил. Я не знаю, где я делаю ошибку... :( Любая помощь ценна.
Это то, что я пробовал для вставки, а второй - для извлечения данных.
- (void)insertNameAndSurnameInDataBase:(NSString *)name surname:(NSString *)surname numbers:(NSArray *)numbers labels:(NSArray *)labels {
AppDelegate *appDel=(AppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *saveObjectContext = [appDel saveManagedObjectContext];
NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
bgContext.parentContext = saveObjectContext;
[bgContext performBlockAndWait:^{
NSError *error;
NameAndSurname *nameAndSurname = [NSEntityDescription insertNewObjectForEntityForName:@"NameAndSurname" inManagedObjectContext:bgContext];
NSString *nSurname = [NSString stringWithFormat:@"%@ %@",name,surname];
if (nSurname.length == 0) {
nameAndSurname.nameSurname = [numbers objectAtIndex:0];
} else {
nameAndSurname.nameSurname = nSurname;
}
if ([bgContext save:&error]) {
} else {
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"NameAndSurname" inManagedObjectContext:bgContext];
// predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"nameSurname =[c] %@", nSurname];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSArray *fetchedObjects = [bgContext executeFetchRequest:fetchRequest error:&error];
if ([fetchedObjects count] > 0){
[numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
id obj2 = [labels objectAtIndex:idx];
obj = [obj stringByReplacingOccurrencesOfString:@" " withString:@""];
ContactNumber *phoneNumber = [NSEntityDescription insertNewObjectForEntityForName:@"ContactNumber" inManagedObjectContext:bgContext];
phoneNumber.number = obj;
phoneNumber.label = obj2;
phoneNumber.nameAndSurname = fetchedObjects[0];
NSError *error;
if ([bgContext save:&error]) {
} else {
}
}];
}
}];
}
- (NSArray *)fetchNameAndSurname {
AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
_managedObjectContext = [appDel managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"NameAndSurname"
inManagedObjectContext:_managedObjectContext];
[fetchRequest setSortDescriptors:@[[[NSSortDescriptor alloc] initWithKey:@"nameSurname" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]]];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSError *error = nil;
NSArray *fetchedObjects = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
return [fetchedObjects valueForKey:@"nameSurname"];
}
Ошибка, которую вы совершаете, заключается в том, что вы не тестируете множество маленьких фрагментов этого кода, которые могут работать не так, как ожидалось. Чтобы устранить неполадки в чем-то подобном, вы должны начать с самого начала и тестировать по одной части за раз. Первая проблема, которую я вижу, — это путаница между контекстами управляемых объектов…
Похоже, что метод saveManagedObjectContext
является геттером для вашего основного контекста управляемого объекта. В английском языке спасти — это глагол, так что это имя метода подразумевает, что он сохраняет какой-то контекст управляемого объекта. Если я прав, вам следует изменить имя saveManagedObjectContext
на возможно mainMangaedObjectContext
.
Оператор _managedObjectContext = [appDel managedObjectContext]
довольно нестандартен, присваивая переменной экземпляра то, что кажется ее геттером. Если, как обычно, _managedObjectContext
является переменной экземпляра, поддерживающей свойство managedObjectContext
, этот оператор не действует.
В первом методе вы используете [appDel saveManagedObjectContext]
, а во втором — [appDel managedObjectContext]
. Похоже, что это должен быть один и тот же контекст, чтобы ваша выборка работала. Они?
ОБНОВИТЬ:
Как вы указали в своем комментарии, это исправляет сохранение, но теперь у вас есть проблема с производительностью - сохранение в постоянное хранилище на диске блокирует пользовательский интерфейс, что и пытался исправить ваш исходный код.
Это решаемая проблема. Решение состоит в том, что ваш контекст основного потока, который взаимодействует с пользователем, должен быть дочерним элементом вашего контекста фонового потока, который взаимодействует с постоянным хранилищем. Это хорошо объясняется с помощью кода в этом Сообщение в блоге Маркуса Зарры, 2015 г.. Для дальнейшего чтения Чад Уилкен опубликовал небольшую вариацию. Оба написаны на Objective-C для вас :)
это метод сохранения контекста объекта управления - (NSManagedObjectContext *) saveManagedObjectContext { if (writerManagedObjectContext! = nil) { returnwriterManagedObjectContext; } NSPersistentStoreCoordinator *coordinator = [самостоятельный постоянныйStoreCoordinator]; if (координатор != nil) {writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [writerManagedObjectContext setPersistentStoreCoordinator:координатор]; } вернуть writeManagedObjectContext; }
В Swift, если я хочу сохранить их все в фоновом контексте, я могу сделать что-то вроде этого: let backgroundContext:NSManagedObjectContext!
backgroundContext = persistentContainer.newBackgroundContext()
но в target -c кажется, что метод newBackgroundContext() не существует.
Смотрите ОБНОВЛЕНИЕ: в моем ответе выше.
Спасибо @Jerry Krinock, в запросе на выборку (второй метод), если я изменю _managedObjectContext = [appDel manageObjectContext]; в NSManagedObjectContext *saveObjectContext = [appDel saveManagedObjectContext]; оно работает. и если я изменю оба метода на основной mainMangaedObjectContext, он сработает.. но моя проблема в том, что мне нужно сохранить много данных из JSON в основных данных во время его сохранения, основной вид приложения начинает блокироваться до тех пор, пока он не завершит свою работу, что я Я пытаюсь сделать всю эту операцию в фоновом потоке, чтобы не блокировать основной поток....