Eu tenho usado DispatchQueue.main.async
por muito tempo para realizar operações relacionadas à IU.
O Swift fornece ambos DispatchQueue.main.async
e DispatchQueue.main.sync
, e ambos são executados na fila principal.
Alguém pode me dizer a diferença entre eles? Quando devo usar cada um?
DispatchQueue.main.async {
self.imageView.image = imageView
self.lbltitle.text = ""
}
DispatchQueue.main.sync {
self.imageView.image = imageView
self.lbltitle.text = ""
}
fonte
DispatchQueue.main.sync
de um thread em segundo plano?async
lá. Quero dizer, uma vez que não há mais nada no tópico depois disso, não faz diferença. Se fosseDispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};
, teria feito sentido. Mas quando não há outro bloqueio, não consigo pensar na vantagem de usarDispatchQueue.main.sync {Oneblock}
novamenteDispatchQueue.main.async {Oneblock}
. Para ambos, eles obterão a prioridade / imediatismo mainQueue e nada os interromperá.Por que simultaneidade?
Assim que você adiciona tarefas pesadas ao seu aplicativo, como o carregamento de dados, ele retarda o trabalho da IU ou até o congela. A simultaneidade permite que você execute 2 ou mais tarefas “simultaneamente”. A desvantagem dessa abordagem é a segurança do thread, que nem sempre é tão fácil de controlar. Fe quando diferentes tarefas desejam acessar os mesmos recursos, como tentar alterar a mesma variável em diferentes threads ou acessar os recursos já bloqueados por diferentes threads.
Existem algumas abstrações das quais precisamos estar cientes.
Filas
Deve ser serial ou simultâneo . Bem como global ou privado ao mesmo tempo.
Com filas seriais, as tarefas serão concluídas uma a uma, enquanto com filas simultâneas, as tarefas serão realizadas simultaneamente e serão concluídas em agendamentos inesperados. O mesmo grupo de tarefas levará muito mais tempo em uma fila serial do que em uma fila simultânea.
Você pode criar suas próprias filas privadas ( seriais ou simultâneas ) ou usar filas globais (sistema) já disponíveis . A fila principal é a única fila serial de todas as filas globais .
É altamente recomendável não realizar tarefas pesadas que não sejam relacionadas ao trabalho da IU na fila principal (por exemplo, carregar dados da rede), mas sim realizá-las nas outras filas para manter a IU descongelada e responsiva às ações do usuário. Se permitirmos que a IU seja alterada nas outras filas, as alterações podem ser feitas em uma programação e velocidade diferentes e inesperadas. Alguns elementos da IU podem ser desenhados antes ou depois de serem necessários. Isso pode travar a IU. Também precisamos ter em mente que, como as filas globais são filas do sistema , algumas outras tarefas podem ser executadas pelo sistema nelas.
Qualidade de serviço / prioridade
As filas também têm diferentes qos (Quality of Service), que define a prioridade de execução da tarefa (da mais alta para a mais baixa aqui):
.userInteractive - fila principal
.userInitiated - para as tarefas iniciadas pelo usuário nas quais o usuário espera por alguma resposta
.utilidade - para as tarefas que leva algum tempo e não requer resposta imediata, por exemplo, trabalhar com dados
.background - para as tarefas que não estão relacionadas com a parte visual e que não são restritas para o tempo de conclusão).
Também existe uma fila
.default que não transfere as informações de qos . Se não foi possível detectar o qos oqos será usado entre .userInitiated e .utility .
As tarefas podem ser realizadas de forma síncrona ou assíncrona .
A função síncrona retorna o controle para a fila atual somente após a conclusão da tarefa. Ele bloqueia a fila e espera até que a tarefa seja concluída.
A função assíncrona retorna o controle para a fila atual logo após a tarefa ter sido enviada para ser executada na fila diferente. Não espera até que a tarefa seja concluída. Não bloqueia a fila.
Problemas comuns.
Os erros mais comuns que os programadores cometem ao projetar os aplicativos simultâneos são os seguintes:
NUNCA chame a função de sincronização na fila principal .
Se você chamar a função de sincronização na fila principal, ela bloqueará a fila, assim como a fila ficará esperando a tarefa ser concluída, mas a tarefa nunca será concluída, pois não será possível nem mesmo iniciar devido à fila já bloqueado. É chamado de impasse .
Quando usar a sincronização? Quando precisamos esperar até que a tarefa seja concluída. Veja quando estamos nos certificando de que alguma função / método não seja duplamente chamada. Sim, temos sincronização e estamos tentando evitar que seja duplamente chamado até que esteja completamente concluído. Aqui está um código para essa preocupação:
Como descobrir o que causou o relatório de falha de erro no dispositivo IOS?
fonte
DispatchQueue.main.sync
de um thread em segundo plano?sync
ou osasync
métodos não têm efeito na fila em que são chamados.sync
bloqueará o encadeamento a partir do qual é chamado e não a fila na qual é chamado. É a propriedadeDispatchQueue
que decide se oDispatchQueue
aguardará pela execução da tarefa (fila serial) ou se poderá executar a próxima tarefa antes que a tarefa atual seja concluída (fila simultânea).Portanto, mesmo quando
DispatchQueue.main.async
é uma chamada assíncrona, uma operação pesada adicionada a ela pode congelar a IU, pois suas operações são executadas em série no encadeamento principal. Se esse método for chamado a partir do thread em segundo plano, o controle retornará a esse thread instantaneamente, mesmo quando a IU parecer estar congelada. Isso ocorre porque aasync
chamada é feita emDispatchQueue.main
fonte
GCD
permite que você execute uma tarefasynchronously
ouasynchronously
[Sobre] [Mais]synchronous
(bloquear e esperar) a função retorna um controle quando a tarefa será concluídaasynchronous
(despachar e prosseguir) retorna um controle imediatamente, despachando a tarefa para iniciar em uma fila apropriada, mas não esperando que ela seja concluída.fonte