Introdução: por que o código legado em Swift precisa de refatoração
Trabalhar com código legado é uma parte inevitável da vida de um desenvolvedor iOS/macOS. Mesmo que o projeto tenha sido originalmente escrito em Swift, com o tempo ele acumula dívida técnica: padrões obsoletos, falta de testes, arquitetura monolítica e mistura de Swift com Objective-C. A refatoração desse código não apenas melhora a legibilidade — ela reduz o custo de manutenção, acelera a adição de novos recursos e diminui o número de bugs.
Neste artigo, vamos explorar técnicas específicas de refatoração de código Swift legado: desde a eliminação de force unwrapping até a migração de MVC para MVVM. Todos os exemplos podem ser aplicados tanto para projetos iOS quanto macOS.
1. Avaliação e preparação: por onde começar a refatoração
Antes de alterar o código, é importante entender seu estado atual. Use as ferramentas integradas do Xcode e métricas.
1.1. Análise de avisos e erros
Abra o projeto no Xcode e vá para o Report Navigator (Cmd+9). Preste atenção em:
- Yellow warnings — APIs obsoletas (deprecated), variáveis não utilizadas.
- Red errors — erros de sintaxe que podem ser consequência de uma migração incompleta do Swift.
- SwiftLint/SwiftFormat — conecte um linter para identificar automaticamente violações de code style.
1.2. Busca por "bandeiras vermelhas" no código
Percorra o projeto usando a busca (Cmd+Shift+F) pelos seguintes padrões:
!— force unwrapping (valores opcionais que crasham o aplicativo).as!— force casting (conversão de tipos sem verificação).try!— ignorar erros.NSObject— herança de NSObject sem necessidade (Swift puro não exige isso).#selector— seletores de string que é melhor substituir por#selectorcom tipo.
// Ruim (legado)let name = user.name! // force unwrap — crash se for nil
// Bom (refatoração)guard let name = user.name else { return}1.3. Escrever testes antes das alterações
Refatoração sem testes é um risco. Se não houver testes, comece adicionando-os para os módulos críticos. Use XCTest para testes unitários e XCUITest para UI.
Exemplo de um teste simples para uma função legada:
class LegacyCalculatorTests: XCTestCase { func testCalculateTotal() { let calculator = LegacyCalculator() let result = calculator.calculateTotal(items: [10, 20, 30]) XCTAssertEqual(result, 60) }}2. Técnicas principais de refatoração de código Swift
Vamos para as etapas práticas que podem ser aplicadas agora mesmo.
2.1. Substituição de force unwrapping por padrões seguros
O problema mais comum em código legado é o uso generalizado de !. Substitua-os por guard let, if let ou ?? (nil-coalescing).
// Antes da refatoraçãofunc getUserName() -> String { return user.name!}
// Depois da refatoraçãofunc getUserName() -> String { return user.name ?? "Unknown"}2.2. Eliminação do Massive View Controller (MVC → MVVM)
Projetos legados frequentemente sofrem com "controladores pesados". Separe a lógica de negócios em serviços ou ViewModels independentes.
// ViewController legado (fragmento)class ProfileViewController: UIViewController { @IBOutlet weak var nameLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Lógica de negócios diretamente no controlador let user = DataManager.shared.fetchUser() nameLabel.text = user.name?.capitalized }}
// Depois da refatoraçãoclass ProfileViewModel { private let userService: UserService var userName: String { return userService.currentUs