Reputation: 2576
To start off, I have a protocol looking like this:
@protocol CryptoDelegate <NSObject>
- (void)cryptoManagerFinishedEncryption;
@end
Theres a singleton named CryptoManager
that has the following function:
- (void)startEncryption:(NSURL *)path withDelegate:(id<CryptoDelegate>)delegate {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// ... some stuff is happening here
[delegate cryptoManagerFinishedEncryption];
});
}
Then I have a self-made MultiPopup
that can display panels (which must extend MultiPopupPanel
to store i.a. a pointer to the popup itself) and switches between these panels using the following code:
- (void)switchTo:(MultiPopupPanel*)panel {
if(self.currentPanel != panel) {
MultiPopupPanel* oldPanel = self.currentPanel;
self.currentPanel = panel;
self.currentPanel.alpha = 0;
self.currentPanel.hidden = NO;
if(oldPanel) {
NSLog(@"Before animation");
[UIView animateWithDuration:0.2f animations:^{
oldPanel.alpha = 0;
} completion:^(BOOL finished) {
NSLog(@"After animation");
oldPanel.hidden = YES;
[UIView animateWithDuration:0.2f animations:^{
self.currentPanel.alpha = 1;
}];
}];
} else {
[UIView animateWithDuration:0.2f animations:^{
self.currentPanel.alpha = 1;
}];
}
}
}
Now I have a panel that extends MultiPopupPanel
and implements the protocol CryptoDelegate
. Within its cryptoManagerFinishedEncryption
implementation I'm calling my switchTo
function that should then switch to another panel.
This is where the application hangs: the message "Before animation" is output immediately. Then the app hangs for 15-20 seconds, then the animation happens, the "After animation" message is output and the new panel shows up.
This only happens when I'm using the +[UIView animateWithDuration...]
from within another thread (through the dispatch_async). If I call the delegate from without the dispatch_async
(= in the main thread) everything goes fine.
Why does this happen? Is it allowed to call animations from async blocks? Any help is greatly appreciated.
Upvotes: 1
Views: 891
Reputation: 119041
You must always call UI related code on the main thread. Not doing so is forbidden and will lead to unexpected results (and often exceptions).
When calling your delegate method you should again use dispatch_async
with the dispatch_get_main_queue
so that the delegate code will run on the main thread and you can update your UI.
See also these Apple docs for more specific information.
Upvotes: 3
Reputation: 1816
any changes to GUI elements as such as animation, size and content should happen on the main thread, otherwise it will have weird effects.
Upvotes: 1