Sobes.tech
Middle

Como é que previnem vazamentos de memória nos seus projetos?

sobes.tech IA

Resposta da IA

Utilizo várias abordagens:

  1. ARC (Contagem Automática de Referências): É o mecanismo principal de gestão de memória em Swift e Objective-C. Conta automaticamente as referências aos objetos e os liberta quando o número de referências chega a zero.
  2. Evitar ciclos de referências fortes: É a causa mais comum de fugas de memória. Uso referências weak ou unowned para quebrar ciclos. Isto acontece frequentemente ao trabalhar com delegados e closures.
  3. Ferramentas de profiling: Uso regularmente ferramentas do Xcode, como Instruments (Allocator, Leaks), para detectar fugas.
  4. Verificação de closures: Reviso cuidadosamente as closures, especialmente ao capturar self, usando listas de captura [weak self] ou [unowned self].
  5. Cancelar inscrições de notificações: Cancelo a inscrição de NotificationCenter e observadores KVO ao destruir objetos.
  6. Remover observadores e temporizadores: Desativo e anulo temporizadores inválidos e removo observadores quando já não são necessários.
  7. Gestão de recursos: Gerencio corretamente recursos como ficheiros, sockets e bases de dados, fechando-os e libertando-os atempadamente.
  8. Revisões de código: Realizo revisões de código regularmente, incluindo para detectar possíveis problemas de gestão de memória.

Exemplo de uso de [weak self] numa closure:

class DataFetcher {
    var completionHandler: (() -> Void)?

    func fetchData() {
        // Uso de weak self para evitar ciclo forte
        DispatchQueue.global().async { [weak self] in
            // Simulação de obtenção de dados
            sleep(1)

            DispatchQueue.main.async {
                // Verificação de nil antes de usar self
                self?.completionHandler?()
            }
        }
    }
}

class ViewController {
    var fetcher: DataFetcher?

    func setupFetcher() {
        fetcher = DataFetcher()
        fetcher?.completionHandler = {
            // Aqui, self pode ser fraco se fetcher ainda existir
            print("Dados obtidos no ViewController")
        }
    }

    deinit {
        print("ViewController desinicializado")
    }
}

Exemplo de uso de weak para um delegado:

protocol DataProcessorDelegate: AnyObject { // AnyObject garante o tipo de referência e impede ciclos fortes com tipos de valor
    func processData(_ data: String)
}

class DataProcessor {
    weak var delegate: DataProcessorDelegate? // Uso de weak para o delegado

    func process(_ data: String) {
        delegate?.processData(data)
    }
}

class AnotherViewController: DataProcessorDelegate {
    let processor = DataProcessor()

    init() {
        processor.delegate = self
    }

    func processData(_ data: String) {
        print("Processando dados: \(data)")
    }

    deinit {
        print("AnotherViewController desinicializado")
    }
}