RestKit и сохранение в CoreData как NSManagedObject

Я использую RestKit, и я хочу анализировать и сохранять элементы в основных данных. У меня есть два json файла:

Первая (категория):

[
   {
     "cat_id": 3371,
     "cat_name": "myName",
     "image": 762
   },
   {
     "cat_id": 3367,
     "cat_name": "anotherName",
     "image": 617
   }
]

И второй (Элементы):

[
  {
    "art_id": "1",
    "node": {
      "author": "name"
    },
    "small_url": 0
  },
  {
    "art_id": "12",
    "node": {
      "author": "anotherName"
    },
    "small_url": 0
  }
]

Итак, основная идея состоит в том, что каждая категория имеет некоторые элементы внутри. Итак, это моя структура CoreData: enter image description here

Я загрузил пример restkit и использовал образец TwitterCoreData. Мой код: AppDelegeta.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSURL *baseURL = [NSURL URLWithString:@"http://globalURL.com"];
    RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
    NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
    objectManager.managedObjectStore = managedObjectStore;

    RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:managedObjectStore];
    categoryMapping.identificationAttributes = @[ @"catId" ];
    [categoryMapping addAttributeMappingsFromDictionary:@{
     @"cat_id": @"catId",
     @"node.author": @"author",
     }];

    RKEntityMapping *elementsMapping = [RKEntityMapping mappingForEntityForName:@"Elements" inManagedObjectStore:managedObjectStore];
    elementsMapping.identificationAttributes = @[ @"artId" ];
    [elementsMapping addAttributeMappingsFromDictionary:@{
     @"art_id": @"artId",
     @"node.author": @"author",
    }];
    [elementsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"category" toKeyPath:@"category" withMapping:categoryMapping]];
    RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:elementsMapping
                                                                                       pathPattern:nil
                                                                                           keyPath:nil
                                                                                       statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
    [objectManager addResponseDescriptor:responseDescriptor];


    [managedObjectStore createPersistentStoreCoordinator];
    NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MyCoreData.sqlite"];
    NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"MyCoreData" ofType:@"sqlite"];
    NSError *error;
    NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
    NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);

    // Create the managed object contexts
    [managedObjectStore createManagedObjectContexts];

    // Configure a managed object cache to ensure we do not create duplicate objects
    managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];



    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

и ViewController.m:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Elements"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"artId" ascending:NO];
fetchRequest.sortDescriptors = @[descriptor];
[[RKObjectManager sharedManager] getObjectsAtPath:@"/detailaddress/:catId" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
    RKLogInfo(@"Load complete: Table should refresh...");
    NSLog(@"%@",mappingResult);
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"LastUpdatedAt"];
    [[NSUserDefaults standardUserDefaults] synchronize];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
    RKLogError(@"Load failed with error: %@", error);
}];

И журнал для отображения показывает мне "нуль". Как сохранить данные из моего первого json (категории) в основные данные с помощью restkit? Помните, что у меня еще нет списка Elements.

Когда я использую создание нового файла для создания подкласса NEManagedObject, у меня есть класс Элементы.

@interface Elements : NSManagedObject

@property (nonatomic, retain) NSNumber * artId;
@property (nonatomic, retain) NSString * author;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSManagedObject *category;

@end

Ответ 1

Я использовал RESTKit до выпуска .20 несколько месяцев назад. Честно говоря, в то время как эта библиотека имеет большие намерения, по моему опыту она заканчивает тем, что тратит гораздо больше времени, чем когда-либо, чтобы спасти меня.

Я использовал его с API, созданным с помощью .NET/MVC, PHP, python/Django/TastyPie, и взломал его, чтобы сделать что-то с Twitter. Все это оказалось очень интересным академическим упражнением, но в конце концов было немного больше. Как старые, так и новые версии RESTKit предполагают ALOT о том, как ваш API будет отвечать на запросы.

С выпуском .10, было реализовано много возможностей для настройки с помощью Obj-C Blocks. Я мог бы перехватить запрос/ответ RKRequest и в значительной степени переопределить все, что собирается сделать RESTKit. Это показалось довольно удивительным. Теперь с выпуском .20 все получилось очень... умный (умный код обычно не очень хорош).

Вместо того, чтобы пытаться оставаться родовым и податливым, RK теперь делает для вас всевозможные "удобные" вещи. Это эффективно устраняет вашу способность застревать его во что бы то ни было (неидеализированная и реалистичная) форма, которую использовал ваш API. На этом этапе я вернулся к написанию всего своего кода, используя AFNetworking. Я предпочел бы взять дополнительное время, чтобы написать свой собственный синтаксический код, и знаю, что, когда мои тесты модулей пройдут, я закончу. Не тратьте время, пытаясь заставить РК вывести значимые сообщения об ошибках.

Другая реальная проблема с RK заключалась в том, что она не является автономной. Он был разработан с предположением, что ваше приложение ВСЕГДА в сети, и просто отражает постоянный магазин в небе. Мои приложения обрабатывают создание контента на устройстве iOS, которое МОЖЕТ ИЛИ НЕ МОЖЕТ быть в сети во время создания контента. Это основная причина, по которой я "настраивал" РК .10. Когда я увидел изменения в .20, я решил, что этого достаточно, и вернулся к тому, чтобы делать вещи по-старому.

Возможно, я просто напишу свой собственный CRUD/RESTful framework, потому что я начинаю уставать тратить время на использование очень специализированных библиотек, которые стараются делать все с минимальной ответственностью, предоставляемой разработчику приложения, насколько это возможно. Такие рамки, как правило, представляют собой швейцарские армейские ножи. Они выглядят действительно потрясающе на бумаге, ОНИ МОГУТ ДЕЛАТЬ ЧТО-НИБУДЬ, тогда вы на самом деле пытаетесь что-то вырезать, и лезвие слишком скучно или ломается. Хорошее программное обеспечение делает очень мало вещей очень хорошо, и если это звучит слишком хорошо, чтобы быть правдой, возможно, это так.

Ответ 2

Итак, вы создали сопоставление для каждого NSManagedObject (и они работают), но теперь вы хотите установить связь между "Категория" и "Элементы".

Проблема заключается в том, что нет информации для отображения элементов, в которых находится категория каждого элемента (уникальный ключ отсутствует). Поэтому вам нужно добавить cat_id в Elements JSON, чтобы обеспечить доступ к этой ключевой ссылке.

// Elements JSON
[
  {
    "cat_id": "1313",
    "art_id": "1",
    "node": {
      "author": "name"
    },
    "small_url": 0
  },
  ...
]
// Edit keypath in relationship mapping
[elementsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"cat_id" toKeyPath:@"category" withMapping:categoryMapping]];

Кроме того, вы можете использовать следующие методы для отслеживания работы картирования.

1) -com.apple.CoreData.SQLDebug 1 // Add in "Arguments" Tab > "Arguments Passed On Launch" 
2) RKLogConfigureByName("RestKit/*", RKLogLevelTrace); // Add to AppDelegate`

Изменить

Отображение

Вы обновили объект Elements в своей модели данных и вашем NSManagedObject с заданным значением? Похоже, вы этого не сделали.

@interface Elements : NSManagedObject

@property (nonatomic, retain) NSNumber * catId;
@property (nonatomic, retain) NSNumber * artId;
@property (nonatomic, retain) NSString * author;
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSManagedObject *category;

@end

Routing

Путь, который вы используете для вашего запроса на получение, не будет работать, потому что @"/detailaddress/:catId" не является допустимым путем. Вы можете, с одной стороны, установить маршрутизацию диспетчера объектов вообще или определить описание ответа.

 // Route for get operation
 [[RKObjectManager sharedManager].router.routeSet addRoute:[RKRoute 
      routeWithClass:[Category class] 
      pathPattern:@"/detailaddress/:catId" 
      method:RKRequestMethodGET]];

 // Response descriptor taken from the Core Data same application 
 RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:categoryMapping pathPattern:@"/detailaddress/:catId" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];     
 [objectManager addResponseDescriptor:responseDescriptor];

 // Use general path for get request
 [[RKObjectManager sharedManager] getObjectsAtPath:@"/detailaddress" ...

Но проверьте, правильно ли настроено отображение и модель данных.