使用dispatch_async加速搜索?

Oma*_*arj 10 iphone objective-c grand-central-dispatch ios ios6

我正在尝试加速我的应用搜索,当有大量数据时它会滞后.

所以我试图分裂搜索谓词UI使用dispatch_async不会dispatch_sync造成任何不同,如果我使用它.

问题是当我使用时dispatch_async,应用程序崩溃有时是因为[__NSArrayI objectAtIndex:]: index "17" beyond bounds.

我现在发生这种情况是因为我们说第一个仍然工作并重新加载tableView并继续搜索将改变数组大小取决于结果所以在这种情况下"CRASH":(

这是我的代码:

    dispatch_async(myQueue, ^{
        searchArray = [PublicMeathods searchInArray:searchText array:allData];
    } );

    if(currentViewStyle==listViewStyle){
        [mytable reloadData];
    }
Run Code Online (Sandbox Code Playgroud)

我试过这个:

    dispatch_async(myQueue, ^{
        NSArray *tmpArray = [PublicMeathods searchInArray:searchText array:allData];
        dispatch_sync(dispatch_get_main_queue(), ^{
            searchArray = tmpArray;
            [mytable reloadData];
        });
    });
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,滞后仍然存在.

更新-1-:

努力工作后搜索Predicate只用了2ms :)但是当用户搜索时键盘仍然滞后,所以我得到的结果之后我唯一能做的就是重新加载表"改变用户界面"这个我认为让它滞后,

所以我搜索分裂这两个操作"在键盘上打字和刷新UI".

更新-2-:

@matehat /sf/answers/1181593031/

@TomSwift /sf/answers/1180623461/

答案像魅力一样工作:)

Mar*_*n R 9

如果searchArray是用作表视图数据源的数组,则只能在主线程上访问和修改此数组.

因此,在后台线程上,您应首先过滤到单独的临时数组.然后将临时数组分配给searchArray主线程:

dispatch_async(myQueue, ^{
    NSArray *tmpArray = [PublicMeathods searchInArray:searchText array:allData];
    dispatch_sync(dispatch_get_main_queue(), ^{
        searchArray = tmpArray;
        [mytable reloadData];
    });
});
Run Code Online (Sandbox Code Playgroud)

更新:使用临时数组应解决崩溃问题,使用后台线程有助于在搜索过程中保持UI响应.但正如在讨论中发现的那样,搜索速度缓慢的一个主要原因可能是复杂的搜索逻辑.

它可能有助于存储额外的"标准化"数据(例如,所有数据都转换为小写,电话号码转换为标准格式等等),以便可以通过更快的不区分大小写的比较来完成实际搜索.


mat*_*hat 4

一种解决方案可能是自愿在搜索之间引入延迟,以便让用户键入并异步执行搜索。就是这样:

首先确保您的队列是这样创建的:

dispatch_queue_t myQueue = dispatch_queue_create("com.queue.my", DISPATCH_QUEUE_CONCURRENT);
Run Code Online (Sandbox Code Playgroud)

在您的类中定义此 ivar(并FALSE在初始化时将其设置为):

BOOL _scheduledSearch;
Run Code Online (Sandbox Code Playgroud)

将此宏写在文件顶部(或任何地方,只需确保其可见)

#define SEARCH_DELAY_IN_MS 100
Run Code Online (Sandbox Code Playgroud)

并且调用此方法而不是第二个片段:

[self scheduleSearch];
Run Code Online (Sandbox Code Playgroud)

其实现是:

- (void) scheduleSearch {
    if (_scheduledSearch) return;
    _scheduledSearch = YES;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)((double)SEARCH_DELAY_IN_MS * NSEC_PER_MSEC));
    dispatch_after(popTime, myQueue, ^(void){
        _scheduledSearch = NO;
        NSString *searchText = [self textToSearchFor];
        NSArray *tmpArray = [PublicMeathods searchInArray:searchText array:allData];
        dispatch_async(dispatch_get_main_queue(), ^{
            searchArray = tmpArray;
            [mytable reloadData];
        });
        if (![[self textToSearchFor] isEqualToString:searchText])
            [self scheduleSearch];
    });
}
Run Code Online (Sandbox Code Playgroud)

[self textToSearchFor]是您应该从中获取实际搜索文本的地方。

它的作用如下:

  • 第一次收到请求时,它将 ivar 设置_scheduledSearchTRUE并告诉 GCD 在 100 毫秒内安排搜索
  • 同时,任何新的搜索请求都不会被处理,因为搜索无论如何都会在几毫秒内发生
  • 当计划的搜索发生时,_scheduledSearchivar 重置为FALSE,以便处理下一个请求。

您可以使用不同的值来SEARCH_DELAY_IN_MS使其满足您的需求。该解决方案应该将键盘事件与搜索生成的工作负载完全解耦。