Deadlocks: Как вы определяете, может ли вызов вызывать небезопасную отрисовку основного потока для iOS? - PullRequest
1 голос
/ 03 сентября 2010

Рисование / рисование всегда должно выполняться в потоке GUI, иначе могут возникнуть тупики! ...

Как вы определяете, может ли вызов вызывать небезопасную отрисовку основного потока для iOS?

Проблема в том, что мы получаем такие стеки, которых нет в главном потоке ...

#19 0x02a788d2 in -[CALayer drawInContext:]
#20 0x02a784b0 in backing_callback
#21 0x02a77d52 in CABackingStoreUpdate
#22 0x02a7701d in -[CALayer _display]
#23 0x02a76ac7 in CALayerDisplayIfNeeded
#24 0x02a689e1 in CA::Context::commit_transaction
#25 0x02a68732 in CA::Transaction::commit
#26 0x02aa604f in CA::Transaction::release_thread
#27 0x918b21e3 in _pthread_tsd_cleanup
#28 0x918b1df6 in _pthread_exit
#29 0x0018bbf2 in +[NSThread exit]
#30 0x0018bb5b in __NSThread__main__
#31 0x918a981d in _pthread_start
#32 0x918a96a2 in thread_start

Как вы узнаете, собираетесь ли вы вызвать это? Существуют ли какие-либо советы по отладке или другие методы, чтобы предупредить себя, когда вы делаете что-то не так.

Ответы [ 2 ]

1 голос
/ 26 февраля 2011

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

Например, если вы хотите перезагрузить UITableView из отдельного потока, вы должны вызвать:

[myTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

И если у вас есть несколько операторов, которые могут вызвать рисование, у вас может быть отдельный метод, который выполняет рисование и обеспечивает его выполнение в основном потоке:

- (void) asyncDoSomeStuff {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Do your stuff
    ...

    // Update UI
    [self performSelectorOnMainThread:@selector(refreshGUI) withObject:nil waitUntilDone:NO];

    [pool release];
}

- (void) refreshGUI {
    [myTableView reloadData];
    [myImageView setImage:[UIImage imageNamed:@"blabla.png"]];
    ...
}

И, наконец, есливы не уверены в том, какой поток будет вызывать конкретный метод, выполняющий какое-либо рисование, тогда в начале метода вы можете добавить следующую инструкцию, которая обеспечит выполнение всего метода в основном потоке:

- (void) myMethod {
    if(![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:NO];
        return;
    }

    // Do your stuff
}

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

1 голос
/ 04 сентября 2010

Я был удивлен, обнаружив, что setNeedsDisplay не помещает в очередь рисунок автоматически в основной поток ....

Кажется, что когда я использую executeSelectorOnMainThread: @selector (setNeedsDisplay) из фонового потока, он не выполняетне производит стек, как указано выше, и рисует на главном потоке как следует.

Возможно, есть веская причина, по которой он не перерисовывает очередь в основном потоке при вызове setNeedsDisplay из фонового потока.Я рассматриваю либо прохождение всего моего кода и проверку того, что setNeedsDisplay вызывается из основного потока, либо возможность создания категории для UIView: setNeedsDisplay, которая будет проверять, является ли текущий поток основным потоком, прежде чем вызывать setNeedsDisplay, в противном случае этобудет повторно запускать setNeedsDisplay в главном потоке.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ ... Я не читал, что это так, я нашел это путем тестирования.

...