iPhone上的JSON和核心数据

Uri*_*zen 93 iphone json core-data objective-c

我有一个核心数据对象图(由两个由多对多关系链接的实体组成).

我很好奇,作为一个相对缺乏经验的iPhone开发人员,是否有人可以推荐一种方法,以及适合iPhone的JSON实现,这将允许我:

  1. 将核心数据记录转换为JSON字符串(同时保持实体之间的关系); 和

  2. 将JSON字符串转换回核心数据对象(再次保留实体之间的关系).

我已经在这一点上搜索了一个教程/代码示例,但没有成功,所以我将非常感激地收到任何帮助.

Mar*_*rra 103

首先,选择一个JSON库来使用,我个人喜欢TouchJSON,但其他几个也很不错.复杂的部分虽然不是很难,但是要将您的托管对象转换为适合转换的结构.我写得这么快,所以它可能有一两个错误:)

你调用的方法是:

- (NSString*)jsonStructureFromManagedObjects:(NSArray*)managedObjects;
- (NSArray*)managedObjectsFromJSONStructure:(NSString*)json withManagedObjectContext:(NSManagedObjectContext*)moc;
Run Code Online (Sandbox Code Playgroud)

实施如下:

- (NSDictionary*)dataStructureFromManagedObject:(NSManagedObject*)managedObject
{
  NSDictionary *attributesByName = [[managedObject entity] attributesByName];
  NSDictionary *relationshipsByName = [[managedObject entity] relationshipsByName];
  NSMutableDictionary *valuesDictionary = [[managedObject dictionaryWithValuesForKeys:[attributesByName allKeys]] mutableCopy];
  [valuesDictionary setObject:[[managedObject entity] name] forKey:@"ManagedObjectName"];
  for (NSString *relationshipName in [relationshipsByName allKeys]) {
    NSRelationshipDescription *description = [[[managedObject entity] relationshipsByName] objectForKey:relationshipName];
    if (![description isToMany]) {
      NSManagedObject *relationshipObject = [managedObject valueForKey:relationshipName];
      [valuesDictionary setObject:[self dataStructureForManagedObject:relationshipObject] forKey:relationshipName];
      continue;
    }
    NSSet *relationshipObjects = [managedObject objectForKey:relationshipName];
    NSMutableArray *relationshipArray = [[NSMutableArray alloc] init];
    for (NSManagedObject *relationshipObject in relationshipObjects) {
      [relationshipArray addObject:[self dataStructureForManagedObject:relationshipObject]];
    }
    [valuesDictionary setObject:relationshipArray forKey:relationshipName];
  }
  return [valuesDictionary autorelease];
}

- (NSArray*)dataStructuresFromManagedObjects:(NSArray*)managedObjects
{
  NSMutableArray *dataArray = [[NSMutableArray alloc] init];
  for (NSManagedObject *managedObject in managedObjects) {
    [dataArray addObject:[self dataStructureForManagedObject:managedObject]];
  }
  return [dataArray autorelease];
}

- (NSString*)jsonStructureFromManagedObjects:(NSArray*)managedObjects
{
  NSArray *objectsArray = [self dataStructuresFromManagedObjects:managedObjects];
  NSString *jsonString = [[CJSONSerializer serializer] serializeArray:objectsArray];
  return jsonString;
}

- (NSManagedObject*)managedObjectFromStructure:(NSDictionary*)structureDictionary withManagedObjectContext:(NSManagedObjectContext*)moc
{
  NSString *objectName = [structureDictionary objectForKey:@"ManagedObjectName"];
  NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:objectName inManagedObjectContext:moc];
  [managedObject setValuesForKeysWithDictionary:structureDictionary];

  for (NSString *relationshipName in [[[managedObject entity] relationshipsByName] allKeys]) {
    NSRelationshipDescription *description = [relationshipsByName objectForKey:relationshipName];
    if (![description isToMany]) {
      NSDictionary *childStructureDictionary = [structureDictionary objectForKey:relationshipName];
      NSManagedObject *childObject = [self managedObjectFromStructure:childStructureDictionary withManagedObjectContext:moc];
      [managedObject setObject:childObject forKey:relationshipName];
      continue;
    }
    NSMutableSet *relationshipSet = [managedObject mutableSetForKey:relationshipName];
    NSArray *relationshipArray = [structureDictionary objectForKey:relationshipName];
    for (NSDictionary *childStructureDictionary in relationshipArray) {
      NSManagedObject *childObject = [self managedObjectFromStructure:childStructureDictionary withManagedObjectContext:moc];
      [relationshipSet addObject:childObject];
    }
  }
  return managedObject;
}

- (NSArray*)managedObjectsFromJSONStructure:(NSString*)json withManagedObjectContext:(NSManagedObjectContext*)moc
{
  NSError *error = nil;
  NSArray *structureArray = [[CJSONDeserializer deserializer] deserializeAsArray:json error:&error];
  NSAssert2(error == nil, @"Failed to deserialize\n%@\n%@", [error localizedDescription], json);
  NSMutableArray *objectArray = [[NSMutableArray alloc] init];
  for (NSDictionary *structureDictionary in structureArray) {
    [objectArray addObject:[self managedObjectFromStructure:structureDictionary withManagedObjectContext:moc]];
  }
  return [objectArray autorelease];
}
Run Code Online (Sandbox Code Playgroud)

现在这是递归的,所以如果你不小心的话,你可以轻松地翻译整个持久性商店.观察您的关系并确保它们仅"关闭"对象树,以便您只获取要翻译的对象.

  • 嗨马库斯.我刚刚尝试了上面的代码(通过一些小修改使其编译,执行似乎无限期地继续,直到应用程序崩溃).很抱歉打扰你,但我很好奇你是否能指出我正确的方向来解决这个问题.它似乎发生在datastructureFromManagedObject方法中的递归... (2认同)

cre*_*der 12

我只是想指出一个小错字,导致代码崩溃,希望这会节省你几分钟.

- (NSArray*)dataStructuresFromManagedObjects:(NSArray*)managedObjects {

    NSMutableArray *dataArray = [[NSArray alloc] init];
    for (NSManagedObject *managedObject in managedObjects) {
        [dataArray addObject:[self dataStructureFromManagedObject:managedObject]];
    }
    return [dataArray autorelease];
}
Run Code Online (Sandbox Code Playgroud)

NSMutableArray *dataArray = [[NSArray alloc] init]; // This should be NSMutableArray

真的应该 NSMutableArray *dataArray = [[NSMutableArray alloc] init];

就这些.

谢谢


Chr*_*lay 10

使用Rails同步核心数据是一个详细的演示文稿,其中包含用于将核心数据对象序列化/反序列化为JSON的示例代码(跳至核心数据部分的幻灯片55).他的示例代码假设一个没有关系的相当简单的模型,但我认为它很容易扩展.

该演示文稿还详细介绍了如何使您的Core Data模型与基于REST的Web应用程序保持同步,并指向一些有用的库,包括ObjectiveResourceASIHTTPRequest.不确定这是不是你想要做的,但是即使是核心数据代码也值得一看.


jos*_*dan 7

如果您NSDate的托管对象中有一个,如上面其中一条评论所述,那么序列化包含该对象的对象时会遇到问题NSDate.一个简单的解决JSONDataRepresentation方法是添加一个NSDate使用objective-c类别的方法.

将这两个文件添加到项目中:

NSdate.h:

#import <Foundation/Foundation.h>

@interface NSDate (jsondatarepresentation) 

- (NSData*) JSONDataRepresentation;

@end
Run Code Online (Sandbox Code Playgroud)

NSDate.m:

#import "NSDate.h"

@implementation NSDate (jsondatarepresentation)

- (NSData*) JSONDataRepresentation {
    return [[[NSNumber numberWithDouble:[self timeIntervalSince1970]] stringValue] dataUsingEncoding:NSUTF8StringEncoding];
}

@end
Run Code Online (Sandbox Code Playgroud)