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

标签 objective-c ios xcode core-data nsxmlparser

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

问题是提要包含新数据和更新数据,因此一旦我解析提要,就会发生以下情况:

  1. 创建一个新实体
  2. 使用 NSXMLParser 填充实体属性
  3. 在 didEndElement 中,获取系统中已有的实体,其 myEntityId 等于我们解析的实体。
  4. 如果实体超过 1 个,则在 Feed 向我们传递新数据时删除旧实体。
  5. 保存实体

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

有没有办法让这个过程变得更简单,并避免在更新时创建新实体并删除旧实体?

我的缩写代码如下:

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;
    }
  }
}

发现角色

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

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

有没有办法让这个过程变得更简单,并避免在更新时创建新实体并删除旧实体?

任何建议都会很棒。

谢谢 丰富

最佳答案

我知道这是一篇旧帖子,但无论如何我都会回答。

您绝对应该查看 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 框架。只要您在数据模型的用户信息部分设置“latedByAttribute”,它就会自动将字典同步到您的托管对象。因此,如果您的对象有一个名为“MyEntityId”的唯一标识属性,则在实体集的用户信息字典中设置“latedByAttribute”-“MyEntityId”,MagicalRecord 会处理它。

如果您需要任何说明,请告诉我。

关于objective-c - 使用 NSXMLParser 和核心数据更新实体的功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8482717/

相关文章:

xcode - Clang 错误 : Reference to NSUTF8StringEncoding is ambiguous

ios - 如何在 iOS 上的 Google map 中徒手绘制?

ios - 如何重复数组中的数据开始数据到结束数据并再次在 IOS objective-c 中开始数据

iphone - UITableViewCells 使用 textViewDidEndEditing 将数据写入 plist

ios - 3D Touch Quick Action 无法快速工作 3

iphone - iOS向大量用户推送通知

ios - 如何将百分比值精确舍入到小数点后两位双倍?

xcode - 使用iOS模拟器调试网络请求,网络请求数据未显示

iOS:从 CNContact 获取数字 key

ios - 以 UIView 作为委托(delegate)和数据源的 UICollectionView