Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Pro Core Data for iOS. Глава №2. Утилитарная часть

Anna | 2.07.2014 | нет комментариев

Сегодня хочу начать свободный перевод книги Михаеля Привата и Роберта Варнера «Pro Core Data for iOS», которую можете скачать по этой ссылке. Всякая глава будет содержать теоретическую и подчасфактическую часть.

image

Оглавление:

  • Глава №1. Приступаем (Фактическая часть)
  • Глава №2. Усваиваем Core Data (Фактическая часть)
  • Глава №3. Хранение данных: SQLite и другие варианты
  • Глава №4. Создание модели данных
  • Глава №5. Трудимся с объектами данных
  • Глава №6. Обработка результатирующих множеств
  • Глава №7. Настройка продуктивности и применяемой памяти
  • Глава №8. Управление версиями и миграции
  • Глава №9. Управление таблицами с применением NSFetchedResultsController
  • Глава №10. Применение Core Data в продвинутых приложениях

Введение

Будем мы создавать вот такую модель:
image

После этого добавим несколько записей и запросим их. Итог будет производиться в консоль, Дабы мы не задавались еще и вопросами визуальными.
Готовы? Тогда поехали!

Изложение

Будем создавать объектный граф нашего любимого источника — Програ.
Есть N основных объектов:

  • Запись в блоге
  • Пользователь
  • Теги
  • Хабы
  • Вопросы
  • Результаты
  • Учетная запись компании

Этого будет довольно.

Какие данные содержит всякий из объектов?

  • Запись в блоге — заголовок, текст
  • Пользователь — ник, карма, рейтинг, пол, аватар, почтовый ящик
  • Тег — название
  • Хаб — название, профильный ли хаб
  • Вопрос — заголовок, текст
  • Результат — текст
  • Учетная запись компании — название организации, рейтинг
Приступаем к работе

Открываем XCode и создаём новейший план Single View Application:

Вводим название плана, префиксы и другое:
image

Знакомое окно:
image

Добавляем Core Data

Добавляем Core Data Framework в план:
image

Создаем модели

Добавить новейший файл -> iOS -> CoreData -> Data Model
image
image

Начнём с записи в блоге.
Создаем новую сущность и называем её Blogpost, добавляем два признака caption (String) и text (String).
image

Создаем новую сущность и называем её User,добавляем признаки avatar (String), email (String), gender(Decimal), karma (Integer 16), nickname (String), rating (Integer 16).
image

Создаем новую сущность и называем её Tag, добавляем каждого один признак name (String).
image

Создаем новую сущность и называем её Hab, добавляем два признака name (String), target (Boolean).
image

Создаем новую сущность и называем её Question, добавляем два признака caption (String), text (String).
image

Создаем новую сущность и называем её Response, добавляем один признак text (String).
image

Создаем новую сущность и называем её Organization, добавляем два признака name (String), rating (Integer 16).
image

Вот что у нас есть в результате:
image

Сейчас займемся установкой отношений между объектами.
У учетной записи компании есть уйма пользователей (работников).
У пользователя есть уйма записей в блоге, у записи в блоге есть уйма тегов и хабов.
У пользователя есть уйма вопросов, а у вопроса уйма результатов.

Начнем с построение связи «учетная запись компании» (один-ко-многим) «пользователи».
Выбираем из списка сущностей Organization и добавляем новую связь нажав на ” ” в разделе Relationships:
image

Так как по умолчанию XCode создаёт связь один-к-одному мы обязаны изменить тип связи:
image

Сейчас у всякой организации есть уйма пользователей. Поле Inverse (обратная связь) мы теперь тоже установим, но заранее добавим новую связь в сущность Пользователя и назовем её organization (организация в которой работает пользователь, а если он не работает нигде, то поле будет null):
image

Сейчас опять откроем редактирование сущности Organization и установим поле Inverse в organization:
image

Вот как стал выглядеть сейчас объектный граф:
image

Испробуйте расставить остальные связи сами, а после этого сверьте с тем, что у меня получилось.
Вы знаете как сделать связь, вы знаете как изменить тип связи с один-к-одному на один-ко-многим — этого будет довольно.
Итоговая картина:
image

Создаем организацию

Теснее имеем в AppDelegate.h такое:

//
//  TMAppDelegate.h
//  Habrahabr
//
//  Created by AndrewShmig on 8/31/13.
//  Copyright (c) 2013 TM. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@class TMViewController;

@interface TMAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) TMViewController *viewController;

@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;

@end

И в AppDelegate.m:

//
//  TMAppDelegate.m
//  Habrahabr
//
//  Created by AndrewShmig on 8/31/13.
//  Copyright (c) 2013 TM. All rights reserved.
//

#import "TMAppDelegate.h"

@implementation TMAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

#pragma mark - Core Data Stack

- (NSManagedObjectModel *)managedObjectModel
{
    if(nil != _managedObjectModel)
        return _managedObjectModel;

    _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];

    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if(nil != _persistentStoreCoordinator)
        return _persistentStoreCoordinator;

    NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                               inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"Habrahabr.sqlite"];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
    if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]){
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}

- (NSManagedObjectContext *)managedObjectContext
{
    if(nil != _managedObjectContext)
        return _managedObjectContext;

    NSPersistentStoreCoordinator *store = self.persistentStoreCoordinator;
    if(nil != store){
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:store];
    }

    return _managedObjectContext;
}

@end

Перепишем способ application:didFinishLaunchingWithOptions: таким образом:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//    Создаем организацию
    NSManagedObject *yandex = [NSEntityDescription insertNewObjectForEntityForName:@"Organization"
                                                            inManagedObjectContext:self.managedObjectContext];
    [yandex setValue:@"Yandex Inc." forKey:@"name"];
    [yandex setValue:@672 forKey:@"rating"];

//    создаем работников Yandex
    NSManagedObject *pupkin = [NSEntityDescription insertNewObjectForEntityForName:@"User"
                                                            inManagedObjectContext:self.managedObjectContext];
    [pupkin setValue:@"VaseaPup" forKey:@"nickname"];
    [pupkin setValue:@"vasilisa@yandex.ru" forKey:@"email"];
    [pupkin setValue:@1 forKey:@"gender"]; // 0 - unknown, 1 - male, 2 - female
    [pupkin setValue:@0 forKey:@"karma"];
    [pupkin setValue:@0 forKey:@"rating"];

    NSManagedObject *gosha = [NSEntityDescription insertNewObjectForEntityForName:@"User"
                                                           inManagedObjectContext:self.managedObjectContext];
    [gosha setValue:@"Goshka" forKey:@"nickname"];
    [gosha setValue:@"gosha.k@yandex.ru" forKey:@"email"];
    [gosha setValue:@0 forKey:@"gender"];
    [gosha setValue:@0 forKey:@"karma"];
    [gosha setValue:@0 forKey:@"rating"];

//    объединяем работников с компанией
    NSMutableSet *employees = [yandex mutableSetValueForKey:@"employees"];
    [employees addObject:pupkin];
    [employees addObject:gosha];

//    сберегаем данные в хранилище
    [self saveContext];

    NSLog(@"Finish!");

    return YES;
}

Запустим приложение. Данные обязаны были быть сохранены. Проверим это.
Обнаружим файл Habrahabr.sqlite:
image

Запустим терминал и проверим конструкцию БД:

AndrewShmigs-MacBook-Pro:~ new$ cd "/Users/new/Library/Application Support/iPhone Simulator/6.1/Applications/95B0716A-9C2C-4BD8-8117-62FB46BB5879"
AndrewShmigs-MacBook-Pro:95B0716A-9C2C-4BD8-8117-62FB46BB5879 new$ ls
Documents	Habrahabr.app	Library		tmp
AndrewShmigs-MacBook-Pro:95B0716A-9C2C-4BD8-8117-62FB46BB5879 new$ cd Documents/
AndrewShmigs-MacBook-Pro:Documents new$ ls
Habrahabr.sqlite
AndrewShmigs-MacBook-Pro:Documents new$ sqlite3 Habrahabr.sqlite 
SQLite version 3.7.12 2012-04-03 19:43:07
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema
CREATE TABLE ZBLOGPOST ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZAUTHOR INTEGER, ZCAPTION VARCHAR, ZTEXT VARCHAR );
CREATE TABLE ZHAB ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZTARGET INTEGER, ZBLOGPOSTS INTEGER, ZNAME VARCHAR );
CREATE TABLE ZORGANIZATION ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZRATING INTEGER, ZNAME VARCHAR );
CREATE TABLE ZQUESTION ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZAUTHOR INTEGER, ZCAPTION VARCHAR, ZTEXT VARCHAR );
CREATE TABLE ZRESPONSE ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZQUESTION INTEGER, ZTEXT VARCHAR );
CREATE TABLE ZTAG ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZBLOGPOST INTEGER, ZNAME VARCHAR );
CREATE TABLE ZUSER ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZKARMA INTEGER, ZRATING INTEGER, ZORGANIZATION INTEGER, ZGENDER DECIMAL, ZAVATAR VARCHAR, ZEMAIL VARCHAR, ZNICKNAME VARCHAR );
CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY, Z_UUID VARCHAR(255), Z_PLIST BLOB);
CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR, Z_SUPER INTEGER, Z_MAX INTEGER);
CREATE INDEX ZBLOGPOST_ZAUTHOR_INDEX ON ZBLOGPOST (ZAUTHOR);
CREATE INDEX ZHAB_ZBLOGPOSTS_INDEX ON ZHAB (ZBLOGPOSTS);
CREATE INDEX ZQUESTION_ZAUTHOR_INDEX ON ZQUESTION (ZAUTHOR);
CREATE INDEX ZRESPONSE_ZQUESTION_INDEX ON ZRESPONSE (ZQUESTION);
CREATE INDEX ZTAG_ZBLOGPOST_INDEX ON ZTAG (ZBLOGPOST);
CREATE INDEX ZUSER_ZORGANIZATION_INDEX ON ZUSER (ZORGANIZATION);
sqlite> select * from ZORGANIZATION;
1|3|1|672|Yandex Inc.
sqlite> select * from ZUSER;
1|7|1|0|0|1|0||gosha.k@yandex.ru|Goshka
2|7|1|0|0|1|1||vasilisa@yandex.ru|VaseaPup
sqlite> 

Добавим сейчас одному из работников вопрос и сделаем какой-то пост.

//    добавляем работнику Гоше вопрос
    NSManagedObject *whoAmI = [NSEntityDescription insertNewObjectForEntityForName:@"Question"
                                                            inManagedObjectContext:self.managedObjectContext];
    [whoAmI setValue:@"Who am I?" forKey:@"caption"];
    [whoAmI setValue:@"Помогите мне узнать себя отменнее." forKey:@"text"];

    NSMutableSet *goshasQuestions = [gosha mutableSetValueForKey:@"questions"];
    [goshasQuestions addObject:whoAmI];

Запустим приложение и проверим БД:

sqlite> select * from ZQUESTION;
1|4|1|4|Who am I?|Помогите мне узнать себя отменнее.
sqlite> 

Добавим блогпост работнику Васе Пупкину:

//    добавляем работнику Васе Пупкину новейший блогпост
    NSManagedObject *newPost = [NSEntityDescription insertNewObjectForEntityForName:@"Blogpost"
                                                             inManagedObjectContext:self.managedObjectContext];
    [newPost setValue:@"yandex.Деньги & yandex.Карты & yandex.ДваСтвола" forKey:@"caption"];
    [newPost setValue:@"Some text" forKey:@"text"];

//    добавляем два Хаба
    NSManagedObject *hab1 = [NSEntityDescription insertNewObjectForEntityForName:@"Hab"
                                                          inManagedObjectContext:self.managedObjectContext];
    [hab1 setValue:@"iOS" forKey:@"name"];
    [hab1 setValue:@YES forKey:@"target"];

    NSManagedObject *hab2 = [NSEntityDescription insertNewObjectForEntityForName:@"Hab"
                                                          inManagedObjectContext:self.managedObjectContext];
    [hab2 setValue:@"Objective-C" forKey:@"name"];
    [hab2 setValue:@YES forKey:@"target"];

    NSMutableSet *habs = [newPost mutableSetValueForKey:@"habs"];
    [habs addObject:hab1];
    [habs addObject:hab2];

    [[pupkin mutableSetValueForKey:@"blogposts"] addObject:newPost];

И итог:

sqlite> select * from ZBLOGPOST;
1|1|1|5|yandex.Деньги & yandex.Карты & yandex.ДваСтвола|Some text
sqlite> select * from ZHAB;
1|2|1|1|1|iOS
2|2|1|1|1|Objective-C
sqlite> 
Итог данных

Выведем всех работников и названия компаний в которых они работают. Код для чтения данных будем писать в том же способе в котором писали и запись данных.

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"User"];
    NSArray *allUsers = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];

    for(NSManagedObject *user in allUsers){
        NSString *nickname = [user valueForKey:@"nickname"];
        NSString *organization = [user valueForKeyPath:@"organization.name"];

        NSLog(@"%@ works at %@", nickname, organization);
    }

Получим приблизительно такой итог (приложение у меня запускалось несколько раз и данные тоже несколько раз были добавлены):

2013-08-31 13:00:27.255 Habrahabr[18148:c07] Goshka works at Yandex Inc.
2013-08-31 13:00:27.257 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
2013-08-31 13:00:27.258 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
2013-08-31 13:00:27.258 Habrahabr[18148:c07] Goshka works at Yandex Inc.
2013-08-31 13:00:27.259 Habrahabr[18148:c07] VaseaPup works at Yandex Inc.
2013-08-31 13:00:27.259 Habrahabr[18148:c07] Goshka works at Yandex Inc.
2013-08-31 13:00:27.260 Habrahabr[18148:c07] Finish!

Обратите внимание на то, как мы получили название организации в которой работает пользователь. Как Вам? А? Я так и думал, что понравится!

В заключение

Экспериментируйте! Не опасайтесь, если что-то сломается, полный план находится по этой ссылке.

Везения и благодарствую за внимание!
Верю вам понравилась утилитарная часть.

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB