NSTimer / NSOperationQueue работает непоследовательно на iphone - PullRequest
0 голосов
/ 30 июня 2011

Я пытаюсь решить проблемы пользовательского интерфейса, связанные с нестабильной работой NSTimer / NSOperationQueue.Я вижу, что независимо от того, использую ли я NSTimer или NSInvocationOperation для запуска приведенного ниже кода, во многих случаях производительность по мере необходимости, но в несколько раз поведение медленное (и, как в примере ниже, код выполняется более 1 секунды иногда).

Вот мой код, который вызывается через NSInvocationOperation:

-(void) progressAsynch{
    for (count = 1; count<=100; count++) {

        // Reposition Label's CGRect.
        [self performSelectorOnMainThread:@selector(moveLabelToNewPosition) withObject:nil waitUntilDone:YES];

        //Update the progress of the progress view
        [self performSelectorOnMainThread:@selector(advanceProgressViewProgress) withObject:nil waitUntilDone:YES];

        //Sleep for 10 millisecs
        [NSThread sleepForTimeInterval:0.01];

        //if the progress view has progressed fully call main thread to to next tasks.
        if(progressView.progress == 1) {
            [self performSelectorOnMainThread:@selector(processResult) withObject:nil waitUntilDone:YES];
        }
    }

}

Код метода, вызываемого NSTimer (срабатывание каждые 10 мс), оченьаналогично приведенному выше, только то, что в нем не будет цикла for.

Очевидно, кажется, что за пределами этой обработки есть что-то, что очень часто замедляет эту производительность.

Любопытно узнать, сталкивались ли вы с подобными проблемами или у вас есть какие-либо указатели / лакомые кусочки, которые могут мне помочь.

Заранее спасибо ..

1 Ответ

0 голосов
/ 30 июня 2011

Обмен между потоками не такой быстрый, а waitUntilDone:YES добавляет дополнительные накладные расходы на синхронизацию потоков и совершенно не нужен (я уверен, что executeSelectors сериализуются). Возможно, вам повезет больше, если вы сделаете что-то вроде

-(void) progressAsynch{
    for (count = 1; count<=100; count++) {
        [self performSelectorOnMainThread:@selector(stuff) withObject:nil waitUntilDone:NO];
        [NSThread sleepForTimeInterval:0.01];
    }
}

Однако, это все еще плохо . Похоже, self является контроллером представления или представления, который будет сохранен NSInvocation и предположительно выпущен в фоновом потоке. Большая часть UIKit не является потокобезопасной; код примера Game Center имеет длину great , чтобы указать, что классы UIKit даже не должны выпускаться в фоновых потоках, потому что выпуск может вызвать -dealloc, что в классах UIKit может быть не поточно-ориентированным. (Уч.)

(Также обратите внимание, что ваш звонок на progressView.progress небезопасен из фоновой цепочки.)

Вы также находитесь в пределе того, что возможно: я почти уверен, что временная привязка iOS составляет 10 мс, что означает, что если что-то еще требует ЦП в любой момент (и есть много фоновых процессов; попробуйте использовать Монитор активности в инструментах когда-нибудь) Ваша анимация может выглядеть запаздывающей.

Наконец, с некоторым кодом воспроизведения звука мы заметили, что NSTimer не очень точен. Я не уверен почему. Я думаю, что мы исправили это с помощью чего-то, что использовало SIGALRM (и код, который, вероятно, был небезопасен, вздох).

Возможно, вам повезет больше с CADisplayLink, который синхронизируется с частотой обновления экрана (я думаю, вы пропустите его [UIScreen mainScreen]) и предназначен для использования анимациями, поэтому он должен работать немного лучше. iOS 3.1+, но я подозреваю, что нет смысла поддерживать 3.0.

...