使用NSXMLParser和核心数据更新实体的功能

时间:2011-12-13 00:05:16

标签: objective-c ios xcode core-data nsxmlparser

我正在使用NSXMLParser和Core Data解析Feed并使用我的iPhone应用中的核心数据添加/更新实体。

问题是Feed包含新数据和更新数据,因此在解析Feed后会发生以下情况:

  1. 创建新实体
  2. 使用NSXMLParser填充实体属性
  3. 在didEndElement中,获取系统中已有的实体,myEntityId等于我们解析的实体。
  4. 如果有超过1个实体,则在Feed向我们传递新数据时删除旧实体。
  5. 保存实体
  6. 我的问题是保存更新信息似乎需要做很多工作,而且代码也总是创建一个新记录,而不仅仅是更新当前记录。

    无论如何,这个过程可以变得更简单,并且在进行更新时无需创建新实体并删除旧实体吗?

    我的缩写代码如下:

    DidStartElement

    - (void)parser:(NSXMLParser *)parser didStartElement...
    {
      if ([elementName isEqualToString:@"AnEntity"])
      {
        NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:_context];
        self.currentEntityObject = newEntity;
      } else 
      {
        if ([elementName isEqualToString:@"Title"] || [elementName isEqualToString:@"MyEntityId"])
        {
          self.currentProperty = [NSMutableString string];
        }  
      }
    }
    

    DidEndElement

    - (void)parser:(NSXMLParser *)parser didEndElement...
    {
      if (self.currentEntityObject)
      {
        if ([elementName isEqualToString:@"Title"]) 
        {
          [self.currentEntityObject setValue:self.currentProperty forKey:@"title"];
    
        } else if ([elementName isEqualToString:@"MyEntityId"]) 
        {
          [self.currentEntityObject setValue:self.currentProperty forKey:@"myEntityId"];
    
        } else if ([elementName isEqualToString:@"AnEntity"])
        {
          [self.currentEntityObject setValue:[NSDate date] forKey:@"lastUpdated"];
    
          NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:_context];
          NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
          [request setEntity:entity];
    
          NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(myEntityId = %@)", [self.currentEntityObject valueForKey:@"myEntityId"]];
          [request setPredicate:predicate];
    
          NSError *error = nil;
          NSArray *array = [_context executeFetchRequest:request error:&error];
    
          int countOfEntityId = array.count;
    
          if (array != nil && countOfEntityId > 1)
          {
            // This is an update so remove old versions
            for(int i=0; i < countOfEntityId; i++)
            {
              if(self.currentEntityObject != [array objectAtIndex:i])
              {
                [_context deleteObject:[array objectAtIndex:i]];
              } 
            } 
          }
    
          error = nil;
          [_context save:&error];
    
          self.currentEntityObject = nil;
        }
      }
    }
    

    FoundCharacters

    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        if (self.currentProperty) 
        {
          [currentProperty appendString:string];
        }
    }
    

    我的问题是保存更新信息似乎需要做很多工作,而且它总是会创建一条新记录,而不仅仅是更新当前记录。

    无论如何,这个过程可以变得更简单,并且在进行更新时无需创建新实体并删除旧实体吗?

    任何建议都会很棒。

    由于 富

1 个答案:

答案 0 :(得分:1)

我意识到这是一个很老的帖子,但无论如何我都会回答。

你一定要查看Saul Mora的MagicRecord。他在任何项目中都很容易使用它,自动与ARC /非ARC一起使用,而CoreData的设置是一个单行程。

首先,我将向您展示我如何解析和更新。

- (void)setUpBeforeParsing
{
    self.currentAttributes = [NSMutableDictionary dictionary];

    self.currentParsedCharacterData = [NSMutableString string];

    self.currentParsedBatch = [NSMutableArray array];

    self.attributesDictionary = myManagedObjectObject.entity.attributesByName;
}

- (void)parser:(NSXMLParser *)parser didStartElement...
{
    for (NSString *attribute in self.attributesDictionary) 
    {
        if ([elementName isEqualToString:attribute]) 
        {
            accumulatingParsedCharacterData = YES;

            [self.currentParsedCharacterData setString:@""];
        }
    }
}


- (void)parser:(NSXMLParser *)parser didEndElement...
{

    if ([elementName isEqualToString:@"myIdentifierThatObjectIsDone"]) 
    {
        [self.currentParsedBatch addObject:[self.currentAttributes copy]];
        [self.currentAttributes removeAllObjects];
        accumulatingParsedCharacterData = NO;
    }
    for (NSString *attribute in self.attributesDictionary) 
    {
        if ([elementName isEqualToString:attribute]) 
        {
            accumulatingParsedCharacterData = NO;

            [self.currentAttributes setObject:[self.currentParsedCharacterData copy] forKey:attribute];
        }
    }
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{
    if (self.accumulatingParsedCharacterData) [self.currentParsedCharacterData appendString:string];
}

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    [MyCoreDataClass MR_importFromArray:self.currentParsedBatch];
}

最重要的是,您可以构建一个字典数组,其中包含您要传输到托管对象的值。一个名叫Tom Harrington的人在cimgf.com上写了一个关于命名对象属性的演示,就像返回的xml或json一样,然后你可以简单地遍历你的属性,直到它与返回的xml元素匹配。这里的美妙之处在于您想要将更多返回的xml保存到对象中,只需向对象添加属性,解析器就会自动同步它。

在解析结束时,您会注意到一个名为的类方法,它来自MagicalRecord框架。只要在数据模型的用户信息部分中设置“relatedByAttribute”,它就会自动将字典同步到您的托管对象。因此,如果您的对象具有名为“MyEntityId”的唯一标识属性,则在您的实体集'relatedByAttribute'的用户信息字典中 - 'MyEntityId'和MagicalRecord负责处理它。

如果您需要任何澄清,请告诉我。