核心数据,重复和删除的 RSS 条目

Posted

技术标签:

【中文标题】核心数据,重复和删除的 RSS 条目【英文标题】:Core Data, duplicate and deleted RSS entries 【发布时间】:2013-01-06 09:58:09 【问题描述】:

我一直在开发 RSS 阅读器,使用核心数据进行缓存。像很多人一样,我想避免重复条目,这导致我提出this 问题,还有this one。 但是,我还想要一件事,我也想让用户能够删除文章,并避免在刷新提要时再次添加已删除的文章,即如果删除的文章仍然存在于提要中。因此,我目前的解决方案是,要在我的托管对象上下文中使用已删除文章的唯一标识符(我如何识别提要中的每个项目)维护另一个实体,我只需将要删除的文章的标识符添加到该实体, 并对其进行检查。

现在,这是我为完成上述所有操作而编写的一段代码。在解析过程中,每次解析提要中的新项目时都会运行此代码。

    dispatch_queue_t checkQueue = dispatch_queue_create("com.feedreader.backgroundchecking", NULL);

    dispatch_async(checkQueue,^
        NSMutableArray *mutablesortedArticles = [NSMutableArray arrayWithArray:self.feeds.sortedArticles];

        if (!mutablesortedArticles) 
            // Handle the error.
        

        if ([[mutablesortedArticles valueForKey:@"identifier"]
             containsObject:article.identifier]) 
            NSLog(@"This article already exists");
            return;
        else 
            NSMutableArray *mutabledeletedArticles = [NSArray arrayWithArray:self.alldeletedArticles];

            if (!mutabledeletedArticles) 
                // Handle the error.
            

            if ([mutabledeletedArticles valueForKey:@"identifier"]
                 containsObject:article.identifier]) 
                NSLog(@"This article has been deleted");
                return;
            else 
                Article *newArticle = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:self.managedObjectContext];

                newArticle.title = article.title;
                newArticle.date = article.date;
                newArticle.link = article.link;
                newArticle.summary = article.summary;
                newArticle.image = article.image;
                newArticle.identifier = article.identifier;
                newArticle.updated = article.updated;
                newArticle.content = article.content;
                newArticle.feed = self.feed;

                dispatch_async(dispatch_get_main_queue(),^
                    NSError *error = nil;
                    [self.managedObjectContext save:&error];
                    if (error) 
                        NSLog(@"%@", error);
                    
                );
            
        
    );

self.feeds.sortedArticles 和 self.alldeletedArticles 都是在解析开始之前从托管对象上下文中获取的。

我的问题开始于运行此代码时,UI 冻结 1-2 秒(我使用托管对象上下文中包含 500 多篇文章的提要进行了尝试)。所以,我想我的问题是,有没有一种更有效的方法来做我想做的事情,一种希望不会冻结 UI 的方法? 也许是处理已删除文章的更好方法?

【问题讨论】:

【参考方案1】:

我的第一个建议是通过向 Article 实体添加“itemDeleted”属性来处理已删除的文章。那么在插入新项目时,您只需检查一个对象列表。

提示:不要将该属性称为“已删除”。isDeletedNSManagedObject 的内置属性,因此可能会导致名称冲突。)

下一个建议是仅在所有项被导入后保存托管对象上下文,而不是在每个项后保存(编辑:另请参阅 Caffeine 的答案,其中是在我写这篇文章时发布的。)

最后,单独搜索所有文章列表中的每个新项目是一种无法很好扩展的模式。 《核心数据编程指南》中的Implementing Find-or-Create Efficiently 描述了一种可能更好的模式:

对于要插入的项目列表,执行获取请求,获取该列表中已存在于数据库中的所有项目, 并行遍历新项目列表和提取列表,找出哪些项目是真正新的并且必须插入。

【讨论】:

+1 使用查找或创建模式的好建议。但是我没有看到后台线程的上下文@SamJ 每个线程都需要创建自己的上下文。您可以通过NSManagedObjectID 在线程之间共享对象。 @flexaddicted 我实际上并没有在后台线程中对托管对象上下文做任何事情。我在后台线程中做的唯一事情是检查已经存在的数组(以前从主线程上的托管对象上下文中获取)以退出和删除文章,并创建一个新条目,我将其保存到主线程上的托管对象上下文中线。后台线程的目的是避免冻结 UI。 @SamJ.: flexaddicted 是对的:你在后台线程中调用 insertNewObjectForEntityForName。但是所有 Core Data 操作都必须在与上下文关联的线程/队列上完成。 @SamJ。您正在后台线程中创建对象。你正在使用来自某个地方的上下文。我错了吗? @SamJ。所以我的建议是创建一个线程/队列上下文并使用它在后台保存。如果您采用这种方法,您应该共享持久协调器。换句话说,您需要将主上下文中使用的持久协调器设置为后面的。我认为您的延迟是由于这个问题造成的。【参考方案2】:

UI 冻结可能是由[self.managedObjectContext save:&error] 引起的,因为将所有对象写入磁盘需要几秒钟。在 ios 5+ 中,一个很好的解决方案是嵌套上下文。有关更多详细信息,请参阅此博文http://www.cocoanetics.com/2012/07/multi-context-coredata/,尤其是末尾的异步保存部分。

【讨论】:

只是关于嵌套上下文的警告。我浪费了很多时间试图解决他们的许多错误。这篇文章总结了很多问题,我也有其他问题。我认为他们还没有准备好。 wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

以上是关于核心数据,重复和删除的 RSS 条目的主要内容,如果未能解决你的问题,请参考以下文章

从RSS导入时如何避免重复结果

从 postgres 数据库中删除重复条目

iCloud 同步 - 核心数据重复条目(绝望的帮助)

核心数据表视图控制器的重复条目以及如何使用 NSFetchedResultsController 处理

根据不同的主键删除重复的sql条目

是否应该在运行 EM 记录链接算法之前删除重复条目?