Einleitung: Warum Legacy-Code in Swift ein Refactoring benötigt
Die Arbeit mit Legacy-Code ist ein unvermeidlicher Teil des Lebens eines iOS/macOS-Entwicklers. Selbst wenn ein Projekt ursprünglich in Swift geschrieben wurde, sammelt es im Laufe der Zeit technische Schulden an: veraltete Patterns, fehlende Tests, monolithische Architektur und die Vermischung von Swift mit Objective-C. Das Refactoring solchen Codes verbessert nicht nur die Lesbarkeit – es senkt die Wartungskosten, beschleunigt das Hinzufügen neuer Features und reduziert die Anzahl der Bugs.
In diesem Artikel werden wir konkrete Refactoring-Techniken für Legacy-Swift-Code durchgehen: von der Beseitigung von Force Unwrapping bis zur Migration von MVC zu MVVM. Alle Beispiele können sowohl für iOS- als auch für macOS-Projekte angewendet werden.
1. Bewertung und Vorbereitung: Wo man mit dem Refactoring beginnt
Bevor man Code ändert, ist es wichtig, seinen aktuellen Zustand zu verstehen. Nutzen Sie die integrierten Tools von Xcode und Metriken.
1.1. Analyse von Warnungen und Fehlern
Öffnen Sie das Projekt in Xcode und gehen Sie zum Report Navigator (Cmd+9). Achten Sie auf:
- Gelbe Warnungen – veraltete APIs (deprecated), ungenutzte Variablen.
- Rote Fehler – Syntaxfehler, die eine Folge einer unvollständigen Swift-Migration sein können.
- SwiftLint/SwiftFormat – Schließen Sie einen Linter an, um automatisch Verstöße gegen den Code Style zu erkennen.
1.2. Suche nach "roten Flaggen" im Code
Durchsuchen Sie das Projekt mit der Suche (Cmd+Shift+F) nach folgenden Patterns:
!– Force Unwrapping (optionale Werte, die die App zum Absturz bringen).as!– Force Casting (Typumwandlung ohne Prüfung).try!– Ignorieren von Fehlern.NSObject– Vererbung von NSObject ohne Notwendigkeit (reines Swift erfordert dies nicht).#selector– String-Selektoren, die besser durch#selectormit Typ ersetzt werden sollten.
// Schlecht (Legacy)let name = user.name! // force unwrap — Absturz bei nil
// Gut (Refactoring)guard let name = user.name else { return}1.3. Schreiben von Tests vor den Änderungen
Refactoring ohne Tests ist ein Risiko. Wenn es keine Tests gibt, beginnen Sie damit, sie für kritische Module hinzuzufügen. Verwenden Sie XCTest für Unit-Tests und XCUITest für UI.
Beispiel eines einfachen Tests für eine Legacy-Funktion:
class LegacyCalculatorTests: XCTestCase { func testCalculateTotal() { let calculator = LegacyCalculator() let result = calculator.calculateTotal(items: [10, 20, 30]) XCTAssertEqual(result, 60) }}2. Grundlegende Techniken des Refactorings von Swift-Code
Kommen wir zu den praktischen Schritten, die Sie sofort anwenden können.
2.1. Ersetzen von Force Unwrapping durch sichere Patterns
Das häufigste Problem in Legacy-Code ist die allgegenwärtige Verwendung von !. Ersetzen Sie sie durch guard let, if let oder ?? (nil-coalescing).
// Vor dem Refactoringfunc getUserName() -> String { return user.name!}
// Nach dem Refactoringfunc getUserName() -> String { return user.name ?? "Unknown"}2.2. Beseitigung von Massive View Controller (MVC → MVVM)
Legacy-Projekte leiden oft unter "fetten" Controllern. Lagern Sie die Geschäftslogik in separate Services oder ViewModels aus.
// Legacy ViewController (Ausschnitt)class ProfileViewController: UIViewController { @IBOutlet weak var nameLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Geschäftslogik direkt im Controller let user = DataManager.shared.fetchUser() nameLabel.text = user.name?.capitalized }}
// Nach dem Refactoringclass ProfileViewModel { private let userService: UserService var userName: String { return userService.currentUs