如何避免 NSXMLParser 中重复的 Core Data 元素?

Posted

技术标签:

【中文标题】如何避免 NSXMLParser 中重复的 Core Data 元素?【英文标题】:How to avoid duplicate Core Data elements in NSXMLParser? 【发布时间】:2012-06-28 21:02:04 【问题描述】:

我正在读取一个基本上如下所示的 XML 文件:

<teams>
    <team id = "A1">
        <player>Tom</player>
        <player>Dick</player>
        <player>Harry</player>
    </team>
    <team id = "A2">
        <player>John</player>
        <player>Tom</player>
    </team>
</teams>

我使用 NSXMLParser 并在 didEndElement 委托方法中创建 Core Data 实体,如下所示:

if ([elementName isEqualToString:@"player"]) 
    if ([nodeContent length] != 0) 
        player = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:savedContext];            
        player.name = nodeContent;
    

didStartElement 上为“团队”做类似的事情。 'nodeContent' 是我从foundCharacters 得到的。到现在为止还挺好。一切正常。然而,在这个例子中,我有一个球员(汤姆)在两支球队打球。这是可能的,但我不希望我的核心数据中有两个汤姆实体。所以,我检查是否已经存在同名的玩家:

    Player *player = nil;

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Player"];
    request.predicate = [NSPredicate predicateWithFormat:@"name = %@", nodeContent];
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
    request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    NSError *error = nil;
    NSArray *players = [savedContext executeFetchRequest:request error:&error];

    if (!players || ([players count] > 1)) 
        NSLog(@"WTF?!");
     else if ([players count] == 0) 
        player = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:savedContext];            
        player.name = nodeContent;
     else 
        player = [players lastObject];
                
    [player addPlaysInTeamObject:team];

...如果是这样的话,我就使用那个实体。如果没有,我像以前一样创建一个新的。

现在,当我在前台同步运行解析时,这一切都有效,但我不想在下载内容时冻结我的应用程序。所以我把所有这些都放在一个线程中。它有时可以正常工作,但偶尔我会在executeFetchRequest 上收到以下错误:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x8177a90> was mutated while being enumerated.'
*** First throw call stack:
(0x12d3022 0x1784cd6 0x12d2bf1 0x41314 0xd5b9 0xceaa25 0x19118f6 0x191dab0 0xce901d 0xcf8d 0xc3a5 0x1f31330 0x1f32439 0x908b9b24 0x908bb6fe)
terminate called throwing an exception(lldb)

当我不使用(前台)UI 时,有时会发生这种情况,但当我触摸任何 UI 元素时总是,即使该 UI 元素不使用我正在加载的数据的背景。我查看了这个论坛并得出结论,这可能是由于解析器填满了数据库,而NSFetchRequest同时使用数据库搜索了某个名称。 (虽然我不太明白,因为这一切都发生在同一个线程中。)

有没有人可以告诉我我做错了什么?

谢谢!

--GB

【问题讨论】:

【参考方案1】:

显然,当另一个线程仍在创建/更新核心数据数据库时,您无法访问核心数据实体。

在这种情况下,我最终将 XML 解析和核心数据创建分开。所以基本上,我解析整个 XML 内容并将其存储在 NSDictionary 中。之后,我使用上面的算法来查找或创建具有该 NSDictionary 的核心数据实体。

【讨论】:

以上是关于如何避免 NSXMLParser 中重复的 Core Data 元素?的主要内容,如果未能解决你的问题,请参考以下文章

重复的访问控制允许来源:* 导致 COR 错误?

如何使用 NSXMLParser 解析同名的父子元素

NSXMLParser 解析属性

在后台线程中使用 MagicalRecord 和 NSXMLParser

如何解析此 xml 并检索 iPhone 中的数据 [重复]

NSXMLParser 将 RSS 解析为自定义对象