Por que não é recomendado sobrecarregar a thread principal no iOS, e quais são as maneiras de evitar isso?
sobes.tech IA
Resposta da IA
O thread principal é responsável por atualizar a interface de utilizador e tratar eventos de UI. Quaisquer operações longas (requisições de rede, cálculos pesados, trabalho com ficheiros) no thread principal irão bloqueá-lo, levando a uma UI "congelada", baixa resposta da aplicação e até ao seu crash (timeout do watchdog).
Formas de evitar a carga no thread principal:
-
Grand Central Dispatch (GCD): Permite executar tarefas de forma assíncrona em filas de fundo.
DispatchQueue.global(): Obter filas globais de fundo com diferentes prioridades.DispatchQueue.main: Fila principal para atualizar a UI.async { ... }: Executar um bloco de código de forma assíncrona.
// executar tarefa pesada em segundo plano DispatchQueue.global(qos: .userInitiated).async { // cálculos pesados ou requisição de rede // atualizar a UI no thread principal DispatchQueue.main.async { // atualizar a interface de utilizador } } -
Queues de Operações (Operation & OperationQueue): Uma abstração de nível superior sobre as filas GCD, suportando dependências entre operações, cancelamento e suspensão.
OperationQueue(): Criar uma fila de operações.Operation: Classe abstrata para tarefas que podem ser adicionadas à fila.addOperation(_:): Adicionar uma operação à fila.
let downloadOperation = BlockOperation { // descarregar dados } let parseOperation = BlockOperation { // analisar dados } // dependência: a análise começa após o download parseOperation.addDependency(downloadOperation) let queue = OperationQueue() queue.addOperation(downloadOperation) queue.addOperation(parseOperation) -
Concorrência (async/await): Abordagem moderna em Swift para programação assíncrona.
async: Marca uma função como assíncrona.await: Aguarda a conclusão de uma operação assíncrona.Task: Criar uma nova tarefa concorrente.
func fetchData() async throws -> Data { let url = URL(string: "https://example.com/data")! let (data, _) = try await URLSession.shared.data(from: url) return data } func updateUI() { Task { do { let data = try await fetchData() // processar dados // atualizar a UI no thread principal automaticamente // (se a tarefa for criada num Actor principal ou DispatchQueue.main) } catch { // tratar erro } } } -
Atores: Impedem condições de corrida ao aceder de diferentes contextos concorrentes, garantindo acesso exclusivo ao seu estado.
actor DataStore { private var data: [String] = [] func addData(_ item: String) { data.append(item) } func getData() -> [String] { return data } } let store = DataStore() Task { await store.addData("item1") }
A escolha entre GCD, Queues de Operações e Concorrência depende da complexidade da tarefa, do nível de controlo necessário e dos requisitos de estruturação do código. A concorrência é a abordagem preferida em aplicações modernas devido à sua legibilidade e segurança.