NSOperations 或 NSThread 用于突发不断相互取消的较小任务?

发布于 2024-09-01 20:02:58 字数 995 浏览 4 评论 0原文

我想看看是否可以针对网络服务进行“键入时搜索”实现,该实现经过充分优化,可以在 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 对象?

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

I would like to see if I can make a "search as you type" implementation, against a web service, that is optimized enough for it to run on an iPhone.

The idea is that the user starts typing a word; "Foo", after each new letter I wait XXX ms. to see if they type another letter, if they don't, I call the web service using the word as a parameter.

The web service call and the subsequent parsing of the result I would like to move to a different thread.

I have written a simple SearchWebService class, it has only one public method:
- (void) searchFor:(NSString*) str;

This method tests if a search is already in progress (the user has had a XXX ms. delay in their typing) and subsequently stops that search and starts a new one. When a result is ready a delegate method is called:

- (NSArray*) resultsReady;

I can't figure out how to get this functionality 'threaded'.
If I keep spawning new threads each time a user has a XXX ms. delay in the typing I end up in a bad spot with many threads, especially because I don't need any other search, but the last one.
Instead of spawning threads continuously, I have tried keeping one thread running in the background all the time by:

- (void) keepRunning {

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

But I can't figure out how to access the "searchFor" method in the "searchObj" object, so the above code works and keeps running. I just can't message the searchObj or retrieve the resultReady objects?

Hope someone could point me in the right direction, threading is giving me grief:)
Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╰つ倒转 2024-09-08 20:02:58

好吧,我花了最后 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];
}

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

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完全不受后台运行的上述任务的影响。

Ok, I spend the last 8 hours reading up on every example out there.
I came to realize that I would have to do some "Proof of Concept" code to see if there even would be a speed problem with building a new thread for "each" keystroke.

It turns out that using NSOperation and NSOperationQueue is more than adequate, both in terms of speed and especially in terms of simplicity and abstraction.

Is called after each keystroke:

- (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];
    }
}

This is mainly to stop the code form initiating a search for keystrokes that are less than 800 ms. apart.
(I would have that a lot lower if it where not for the small touch keyboard).

If it is allowed to time out, it is time to search.

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

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

Cancel all operations that is currently in the queue. This is called every time a new search is
started, it makes sure that the search operation already in progress gets closed down in an orderly fashion, it also makes sure that only 1 thread is ever in a "not-cancelled" state.

The implementation for the ISSearchOperation is really simple:

@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

There are two major steps, the downloading of the data from the web service and the parsing.
After each I check to see if the search has been canceled by [NSOperationQueue cancelAllOperations] if it has, then we return and the object is nicely cleaned up in the dealloc method.

I will probably have to build in some sort of time out for both the web service and the parsing, to prevent the queue from choking on a KIA object.

But for now this is actually lightning fast, in my test I am searching an 16.000 entries dictionary and having Xcode NSLog it to the screen (slows things down nicely), each 800 ms. I issue a new search string via a timer and thereby canceling the old before it has finished its NSLog results to screen loop.
NSOperationQueue handles this with no glitches and never more that a few ms. of two threads being executed. The UI is completely unaffected by the above tasks running in the background.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文