在 Objective-c 中使用调度队列

Posted

技术标签:

【中文标题】在 Objective-c 中使用调度队列【英文标题】:Working with dispatch queues in Objective-c 【发布时间】:2012-10-23 20:38:47 【问题描述】:

我对 ios 很陌生,我正在从网络服务获取数据。我将这些数据存储到核心数据中。目前,我正在第一个视图控制器(tableview)中加载我的所有数据。但这需要大约 10 分钟才能填满 tableview 并将所有数据存储在核心数据库中。所以我想知道最佳实践是什么。所以我想使用调度队列。但是最好的使用方法是什么?

第一种方法

    首先从第一个视图存储数据 用这些数据填充表格视图 将其余数据存储在 db 中。

但是,如果您转到下一个视图并且没有加载所有数据怎么办?

第二种方法

    从第一个视图存储数据 用这些数据填充 tableview? 当用户进入第二个视图时,存储第二个视图的数据 使用此数据加载第二个视图。

您始终可以正确存储数据,但用户仍然需要等待才能使用该应用程序。 (因为没有为该视图加载数据。)

目前我使用的是第一种方法。并使用调度队列。我就是这样用的。

- (void)fetch1:(UIManagedDocument *)document

    dispatch_queue_t fetchQ = dispatch_queue_create("NewsFetch", NULL);
    dispatch_async(dispatch_get_main_queue(), ^
        //store data in core database for firstViewController and save document.
        [document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
        [self loadFirstTableView];
        [self fetch2];
    );
    dispatch_release(fetchQ);


- (void)fetch2:(UIManagedDocument *)document

    dispatch_queue_t fetchAlbum = dispatch_queue_create("Album fetcher", NULL);
    dispatch_async(fetchAlbum, ^
       //store data for secondViewController
        [document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];


    dispatch_release(fetchAlbum);

谁能帮帮我?

亲切的问候

编辑

我如何从 web 服务获取我的数据是通过以下方式。

 NSArray *news = [GenkData getNews]; //gets all the data from webservice as JSON
        for (NSDictionary *genkInfo in news) 
            [News newsWithGenkInfo:genkInfo  inManagedObjectContext:document.managedObjectContext];
        
        [document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];

这就是我设置表格视图的方式。

- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"News"];

    request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:YES],nil];

    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                managedObjectContext:self.genkDatabase.managedObjectContext
                                sectionNameKeyPath:nil
                                cacheName:nil];


【问题讨论】:

“所以我想知道最佳实践是什么。所以我想使用调度队列。”你好掉头。您应该更好地描述您的问题并让人们提出解决方案,而不是跳到 GCD 上。 我不知道您的性能问题。使用 Instruments 来确定您的瓶颈,然后在确定瓶颈位置后询问。此外,您对UIManagedDocument 的使用是完全错误的。这些调用是异步的。这就是他们有完成块的原因。 【参考方案1】:

当您遇到性能问题时,您的第一反应应该是引入多线程。这增加了额外的复杂性,不应掉以轻心,并且需要非常小心地关注架构。

相反,我强烈建议您查看 Ray Wenderlich 的优秀教程,了解如何将 NSFetchedResultsController 连接到 UITableView

NSFetchedResultsController 允许您仅加载您需要的数据,并会在用户请求时自动获取批量内容。它会节省你的记忆;这将花费更少的时间;它会让您的用户满意。

在此处查看教程:http://www.raywenderlich.com/999/core-data-tutorial-how-to-use-nsfetchedresultscontroller

编辑

因此,根据您的修改,我将按照以下方式设计您的要求。

    您应该使用异步 HTTP 请求从 Web 服务中获取数据。使用NSURLRequestAFNetworking 之类的库使这变得更容易。

    既然您是从 Web 服务获取数据,那么您真的需要将该数据插入到 Core Data 中吗?更简单的方法是简单地缓存 HTTP 响应,然后直接从中加载表视图。

    现在您已经有了 HTTP 响应,请告诉 UITableView 重新加载。当它重新加载时,您使用委托方法向它提供表数据。如果您不使用 Core Data,则无需再与NSFetchedResultsController 混淆。

如果您的 Web 服务返回大量数据,您可能应该编写一些分页机制来批量获取结果。它会这样工作:当用户到达表格视图的末尾时,您将发送另一个请求以获取接下来的 25 个项目。一般的经验法则:在需要之前不要获取数据。

最后,通过所有这些获取,您将想要告诉您的用户发生了什么。请查看SVProgressHUD

希望对您有所帮助。

【讨论】:

我正在使用这个 NSFetchedResultsController 来设置我的表格视图。但是还是很慢。 然后发布该代码。我已经在几分之一秒内加载了半百万行的核心数据表。您在获取请求中做错了什么。 如果我理解正确,您说“在需要时将数据加载到核心数据库中”。正确吗? 不,您应该只在需要时将数据从 Core Data 加载到内存中。您说“我正在加载我的所有数据”,这是不推荐的。 NSFetchedResultsController 允许您批量加载数据。有关详细信息,请参阅文档。 他指的是 NSFetchRequest 的 setBatchSize 方法,它可以让你在你的 fetch 结果上拥有多条记录。

以上是关于在 Objective-c 中使用调度队列的主要内容,如果未能解决你的问题,请参考以下文章

Objective-c中如何基于uiswitch ON/OFF案例实现删除和重新调度本地通知

快速调用objective-c类方法

什么是Objective-C中Android的“Spannable”等价物

Yarn调度队列

获取当前调度队列?

Swift正在蚕食Objective-C的市场