Como passar em uma entrevista de Swift: nível avançado
\n\nA entrevista para uma posição de Desenvolvedor iOS Sênior ou Team Lead não é apenas uma verificação de conhecimento de sintaxe. Os entrevistadores querem ver uma compreensão profunda do funcionamento interno do Swift, a capacidade de projetar arquitetura e evitar armadilhas. Neste artigo, analisaremos 4 blocos de perguntas de nível avançado que são frequentes em entrevistas. Cada bloco é acompanhado por exemplos de código e explicações que o ajudarão a responder com confiança a qualquer pergunta.
\n\n1. Automatic Reference Counting (ARC) e gerenciamento de memória
\n\nARC é um dos tópicos-chave. O entrevistador pode perguntar sobre ciclos de referência forte (strong reference cycles) e maneiras de quebrá-los.
Pergunta: O que é uma capture list e como ela ajuda a evitar retain cycle em closures?
\n\nClosures em Swift são tipos de referência. Se uma closure captura self (por exemplo, uma propriedade de classe), e o próprio objeto armazena essa closure, ocorre um ciclo. A solução é usar uma capture list com os modificadores [weak self] ou [unowned self].
class NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n // PERIGOSO: captura de referência forte\n onComplete = {\n self.processData() // retain cycle!\n }\n\n // CORRETO: captura fraca\n onComplete = { [weak self] in\n guard let self = self else { return }\n self.processData()\n }\n }\n\n func processData() { print("Processing...") }\n deinit { print("NetworkManager deallocated") }\n}\n\nImportante: use unowned self apenas se tiver certeza de que o objeto estará vivo no momento da chamada da closure. Caso contrário, use weak self.
2. Genéricos (Generics) e protocolos com associatedtype
\n\nO nível avançado implica a capacidade de escrever código genérico e entender as limitações de protocolos com tipos associados.
\n\nPergunta: Qual é a diferença entre um protocolo com associatedtype e um protocolo com genéricos? Como usar Opaque Types (some)?
\n\nUm protocolo com associatedtype não pode ser usado como um tipo independente. Para ocultar o tipo concreto, usa-se a palavra-chave some (opaque return type), que foi introduzida no Swift 5.1.
// Protocolo com tipo associado\nprotocol Container {\n associatedtype Item\n mutating func append(_ item: Item)\n var count: Int { get }\n}\n\n// Implementação\nstruct IntBox: Container {\n typealias Item = Int\n private var items: [Int] = []\n mutating func append(_ item: Int) { items.append(item) }\n var count: Int { items.count }\n}\n\n// Função retorna "some Container" — o tipo concreto está oculto\nfunc makeContainer() -> some Container {\n return IntBox()\n}\n\n// Uso\nvar box = makeContainer()\nbox.append(42)\nprint(box.count) // 1\n\nEssa abordagem permite alterar a implementação de forma flexível sem modificar o código de chamada. Isso é frequentemente perguntado no contexto de SwiftUI e do padrão Builder.
\n\n3. Multithreading: GCD e OperationQueue
\n\nO conhecimento de Grand Central Dispatch e operações é um requisito obrigatório para qualquer desenvolvedor iOS. Perguntas avançadas abordam deadlock, thread safety e prioridades.
\n\nPergunta: Como evitar Data Race ao trabalhar com dados compartilhados de diferentes threads?
\n\nData Race ocorre quando duas threads leem e escrevem simultaneamente na mesma área de memória sem sincronização. A solução é usar uma fila serializada ou um bloqueio.
\n\nclass ThreadSafeCounter {\n private var count = 0\n // Fila serializada para sincronização\n private let queue = DispatchQueue(label: "com.example.counter")\n\n func increment() {\n queue.sync {\n count += 1\n }\n }\n\n func getCount() -> Int {\n return queue.sync