3

我想看看我是否可以针对 Web 服务进行“键入时搜索”实现,该实现已经优化到足以在 iPhone 上运行。

这个想法是用户开始输入一个单词;“Foo”,在每个新字母之后我等待 XXX 毫秒。看看他们是否输入了另一个字母,如果没有,我使用这个词作为参数调用 Web 服务。

Web 服务调用和结果的后续解析我想移到不同的线程。

我写了一个简单的 SearchWebService 类,它只有一个公共方法: - (void) searchFor:(NSString*) str;

此方法测试搜索是否已在进行中(用户在键入时有 XXX 毫秒延迟),随后停止该搜索并开始新的搜索。当结果准备好时,调用委托方法:

- (NSArray*) resultsReady;

我不知道如何让这个功能“线程化”。如果我每次用户有 XXX 毫秒时都不断产生新线程。打字延迟我最终陷入了一个有很多线程的不好的地方,特别是因为我不需要任何其他搜索,但最后一个。我没有连续产生线程,而是尝试通过以下方式使一个线程始终在后台运行:

- (void) keepRunning {

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    SearchWebService *searchObj = [[SearchWebService alloc] init];
    [[NSRunLoop currentRunLoop] run]; //keeps it alive  
    [searchObj release];
    [pool release];
}

但我不知道如何访问“searchObj”对象中的“searchFor”方法,所以上面的代码工作并继续运行。我只是无法发送消息searchObj或检索resultReady对象?

希望有人能指出我正确的方向,线程让我感到悲伤:) 谢谢。

4

1 回答 1

2

好的,我花了最后 8 个小时阅读那里的每个示例。我开始意识到我必须做一些“概念验证”代码,看看是否会为“每个”击键构建一个新线程存在速度问题。

事实证明,使用 NSOperation 和 NSOperationQueue 是绰绰有余的,无论是在速度方面,尤其是在简单性和抽象方面。

在每次击键后调用:

- (void) searchFieldChanged:(UITextField*) textField {

    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    NSString *searchString = textField.text;

    if ([searchString length] > 0) {

        [self performSelector:@selector(doSearch:) withObject:textField.text afterDelay:0.8f];
    }
}

这主要是为了阻止代码表单开始搜索小于 800 毫秒的击键。分开。(如果不是小型触摸键盘,我会低很多)。

如果允许超时,则该进行搜索了。

- (void) doSearch:(NSString*) searchString {

    [queue cancelAllOperations];
    ISSearchOperation *searchOperation = [[ISSearchOperation alloc] initWithSearchTerm:searchString];
    [queue addOperation:searchOperation];
    [searchOperation release];
}

取消当前在队列中的所有操作。每次启动新搜索时都会调用它,它确保已经在进行的搜索操作以有序的方式关闭,它还确保只有一个线程处于“未取消”状态。

ISSearchOperation 的实现非常简单:

@implementation ISSearchOperation

- (void) dealloc {

    [searchTerm release];
    [JSONresult release];
    [parsedResult release];
    [super dealloc];
}

- (id) initWithSearchTerm:(NSString*) searchString {

    if (self = [super init]) {

        [self setSearchTerm:searchString];
    }

    return self;
}

- (void) main {

    if ([self isCancelled]) return;
    [self setJSONresult:/*do webservice call synchronously*/];
    if ([self isCancelled]) return; 
    [self setParsedResult:/*parse JSON result*/];
    if ([self isCancelled]) return;

    [self performSelectorOnMainThread:@selector(searchDataReady:) withObject:self.parsedResult waitUntilDone:YES];
}

@end

有两个主要步骤,从 Web 服务下载数据和解析。每次我检查搜索是否被取消后,[NSOperationQueue cancelAllOperations]如果它已经取消,然后我们返回并且在 dealloc 方法中很好地清理了对象。

我可能必须为 Web 服务和解析设置某种超时,以防止队列在KIA对象上阻塞。

但是现在这实际上是闪电般的快,在我的测试中,我正在搜索一个 16.000 个条目的字典,并让 Xcode NSLog 将其记录到屏幕上(很好地减慢速度),每 800 毫秒。我通过计时器发出一个新的搜索字符串,从而在它完成其 NSLog 结果到屏幕循环之前取消旧的。NSOperationQueue 可以毫无问题地处理这个问题,而且不会超过几毫秒。正在执行的两个线程。UI 完全不受上述在后台运行的任务的影响。

于 2010-05-16T12:05:24.510 回答