Чтение онлайн

ЖАНРЫ

iOS. Приемы программирования

Нахавандипур Вандад

Шрифт:

В этом разделе предполагается, что вы уже создали модель управляемых объектов Person. Подобная модель показана на рис. 16.20.

Рис. 16.20. Простая модель Core Data, используемая в этом разделе

При работе с этой моделью я заполню стек 1000 объектов Person, как показано в следующем коде, а уже потом попробую выбирать информацию из стека:

— (void) populateDatabase{

for (NSUInteger counter = 0; counter < 1000; counter++){

Person *person =

[NSEntityDescription

insertNewObjectForEntityForName: NSStringFromClass([Person class])

inManagedObjectContext: self.managedObjectContext];

person.firstName = [NSString stringWithFormat:@"First name %lu",

(unsigned long)counter];

person.lastName = [NSString stringWithFormat:@"Last name %lu",

(unsigned long)counter];

person.age = @(counter);

}

NSError *error = nil;

if ([self.managedObjectContext save:&error]){

NSLog(@"Managed to populate the database.");

} else {

NSLog(@"Failed to populate the database. Error = %@", error);

}

}

Обратите

внимание: я использую класс NSStringFromClass для преобразования имени класса Person в строку и для последующего инстанцирования объектов такого типа. Некоторые программисты предпочитают типизировать Person как строковый литерал. Но если жестко запрограммировать вашу строку таким образом, может возникнуть проблема. Допустим, позже вы решите изменить имя Person в стеке Core Data, а жестко закодированная строка никуда не денется. Она может привести к аварийному завершению вашего приложения во время исполнения, так как объекта модели с именем Person больше не существует. Но если вы примените вышеупомянутую функцию для преобразования имени класса в обычную строку, то при изменении имени класса или отсутствии такого класса получите ошибку времени компиляции. Такие ошибки выявляются еще до ввода приложения в работу, и у вас будет время их исправить.

Прежде чем продолжать обсуждение, оговорюсь: предполагается, что вы уже заполнили базу данных с помощью последнего написанного нами метода. Далее в общих чертах изложено, как мы собираемся выполнять выборку в фоновом контексте.

1. Создаем фоновый контекст с помощью метода-инициализатора initWithConcurrencyType:, относящегося к классу NSManagedObjectContext, затем передаем этому методу значение NSPrivateQueueConcurrencyType. В результате получаем контекст, имеющий собственную закрытую очередь диспетчеризации. Поэтому, если вызвать в контексте блок performBlock:, этот блок будет выполнен в закрытой фоновой очереди.

2. Затем мы собираемся задать в фоновом контексте значение свойства persistentStoreCoordinator, которое будет равно экземпляру координатора нашего постоянного хранилища данных. Таким образом мы свяжем фоновый контекст с координатором постоянного хранилища. В результате, если выполнить выборку в фоновом контексте, эта операция позволит получить данные прямо с диска или из любого другого места, где их может хранить координатор.

3. Выполняем в фоновом контексте вызов performBlock:, а затем даем запрос на выборку. В рамках этого запроса требуется найти в стеке Core Data всех людей, чей возраст относится к диапазону от 100 до 200. Подчеркиваю: реалистичность эксперимента нас в данном случае не волнует. Я хочу лишь продемонстрировать, как действует выборка данных в фоновом режиме. Создавая запрос выборки данных, мы устанавливаем его свойство resultType в значение NSManagedObjectIDResultType. Так мы гарантируем, что результаты, возвращаемые после выполнения этого запроса на выборку, состоят не из управляемых объектов как таковых, а только из ID этих объектов. Как объяснялось ранее, мы не собираемся выбирать сами управляемые объекты, поскольку при выборке этих объектов в фоновом контексте не сможем использовать их в основном потоке. Итак, в фоновом контексте мы только выбираем их ID, а преобразуем эти ID в реальные управляемые объекты уже в главном контексте.

После этого такие объекты можно использовать в основном потоке.

Вот как создается запрос на выборку:

— (NSFetchRequest *) newFetchRequest{

NSFetchRequest *request = [[NSFetchRequest alloc]

initWithEntityName:

NSStringFromClass([Person class])];

request.fetchBatchSize = 20;

request.predicate =

[NSPredicate predicateWithFormat:@"(age >= 100) AND (age <= 200)"];

request.resultType = NSManagedObjectIDResultType;

return request;

}

А вот как мы будем создавать фоновый контекст и выполнять в нем запрос на выборку данных:

— (BOOL) application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

__weak NSManagedObjectContext *mainContext = self.managedObjectContext;

__weak AppDelegate *weakSelf = self;

__block NSMutableArray *mutablePersons = nil;

/* Создаем фоновый контекст */

NSManagedObjectContext *backgroundContext =

[[NSManagedObjectContext alloc]

initWithConcurrencyType: NSPrivateQueueConcurrencyType];

backgroundContext.persistentStoreCoordinator =

self.persistentStoreCoordinator;

/* Выполняем блок в фоновом контексте */

[backgroundContext performBlock: ^{

NSError *error = nil;

NSArray *personIds = [backgroundContext

executeFetchRequest: [weakSelf newFetchRequest]

error:&error];

if (personIds!= nil && error == nil){

mutablePersons = [[NSMutableArray alloc]

initWithCapacity: personIds.count];

/* Теперь переходим в главный контекст и получаем эти объекты

в главном контексте, исходя из их ID */

dispatch_async(dispatch_get_main_queue, ^{

for (NSManagedObjectID *personId in personIds){

Person *person = (Person *)[mainContext

objectWithID: personId];

[mutablePersons addObject: person];

}

[weakSelf processPersons: mutablePersons];

});

} else {

NSLog(@"Failed to execute the fetch request.");

}

}];

self.window = [[UIWindow alloc]

initWithFrame: [[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}

Этот код собирает все управляемые объекты в виде массива, а затем вызывает в делегате нашего приложения метод processPersons:, обрабатывающий результаты массива. Напишем этот метод следующим образом:

Поделиться с друзьями: