NSOperations или NSThread для очередей небольших задач, которые постоянно отменяют друг друга? - PullRequest
3 голосов
/ 15 мая 2010

Хотелось бы узнать, смогу ли я реализовать реализацию «поиск по мере ввода» для веб-службы, которая достаточно оптимизирована для его работы на iPhone.

Идея состоит в том, что пользовательначинает набирать слово;«Фу», после каждого нового письма жду XXX мс.чтобы увидеть, набирают ли они другую букву, если нет, я вызываю веб-службу, используя слово в качестве параметра.

Вызов веб-службы и последующий анализ результата, который я хотел бы переместить надругая нить.

Я написал простой класс 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];
}

Но я не могу понять, как получить доступ к методу searchFor в searchObjобъект, поэтому приведенный выше код работает и продолжает работать.Я просто не могу отправить сообщение searchObj или получить объекты resultReady?

Надеюсь, кто-нибудь может указать мне правильное направление, многопоточность доставляет мне горе :) Спасибо.

1 Ответ

2 голосов
/ 16 мая 2010

Хорошо, я провожу последние 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

Существует два основных этапа: загрузка данных из веб-службы и анализ. После каждой проверки я проверяю, был ли поиск отменен с помощью [NSOperationQueue cancelAllOperations], если он был выполнен, то мы возвращаемся, и объект хорошо очищается с помощью метода dealloc.

Мне, вероятно, придется установить какое-то время ожидания как для веб-службы, так и для синтаксического анализа, чтобы предотвратить засорение очереди объектом KIA .

Но сейчас это на самом деле молниеносно, в моем тесте я искал словарь из 16.000 записей и выводил Xcode NSLog на экран (приятно замедляет работу) каждые 800 мс. Я выдаю новую строку поиска через таймер и тем самым отменяю старую, прежде чем она закончит свои результаты NSLog для цикла экрана. NSOperationQueue обрабатывает это без сбоев и не более нескольких мс. двух потоков выполняется. На пользовательский интерфейс не влияют вышеуказанные задачи, выполняющиеся в фоновом режиме.

...