Na verdade, é muito simples.
Quando você, por exemplo, chama o método reloadData do UICollectionView ou o método invalidateLayout do layout, você faz o seguinte:
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
dispatch_async(dispatch_get_main_queue(), ^{
//your stuff happens here
//after the reloadData/invalidateLayout finishes executing
});
Por que isso funciona:
O thread principal (que é onde devemos fazer todas as atualizações da IU) hospeda a fila principal, que é serial por natureza, ou seja, funciona no estilo FIFO. Portanto, no exemplo acima, o primeiro bloco é chamado, o qual tem nosso reloadData
método sendo chamado, seguido por qualquer outra coisa no segundo bloco.
Agora, o thread principal também está bloqueando. Então se você éreloadData
leva 3s para executar, o processamento do segundo bloco será adiado por esses 3s.