Einführung
Die Leistung von mobilen und Desktop-Anwendungen ist ein Schlüsselfaktor, der die Benutzererfahrung beeinflusst. Benutzer erwarten, dass Anwendungen schnell, flüssig und ohne Verzögerungen arbeiten. Für Swift-Entwickler, die Anwendungen für das Apple-Ökosystem (iOS, macOS, watchOS, tvOS) erstellen, wird die Leistungsoptimierung nicht nur wünschenswert, sondern zu einer zwingenden Aufgabe. In diesem Artikel betrachten wir die wichtigsten Methoden zur Optimierung der Leistung von Swift-Anwendungen, von der Speicherverwaltung bis zur effizienten Arbeit mit Multithreading. Sie erfahren, wie Sie typische Fehler vermeiden und Ihre Anwendung so schnell wie möglich machen.
1. Speicherverwaltung und ARC
Swift verwendet Automatic Reference Counting (ARC) zur Speicherverwaltung. Eine falsche Verwendung von ARC kann jedoch zu Speicherlecks und Leistungseinbußen führen. Das Hauptproblem sind zyklische Referenzen (retain cycles).
1.1. Vermeiden Sie zyklische Referenzen
Zyklische Referenzen entstehen, wenn zwei Objekte aufeinander verweisen und ARC ihren Speicher nicht freigeben kann. Verwenden Sie weak oder unowned, um den Zyklus zu unterbrechen.
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\\(name) freigegeben") }}
class Apartment { let unit: String weak var tenant: Person? // weak verhindert zyklische Referenz init(unit: String) { self.unit = unit } deinit { print("Apartment \\(unit) freigegeben") }}
var john: Person? = Person(name: "John")var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4Aunit4A?.tenant = johnjohn = nilunit4A = nil// Beide Objekte werden freigegeben1.2. Verwenden Sie Wertetypen (Structs) anstelle von Referenztypen (Classes)
Strukturen (structs) werden auf dem Stack gespeichert, was schneller ist als die Speicherung auf dem Heap (heap) bei Klassen. Verwenden Sie Strukturen für kleine, unveränderliche Daten.
struct Point { var x: Double var y: Double}
class PointClass { var x: Double var y: Double init(x: Double, y: Double) { self.x = x self.y = y }}
// Leistungstestlet count = 1_000_000var start = CFAbsoluteTimeGetCurrent()var points = [Point](repeating: Point(x: 0, y: 0), count: count)for i in 0..<count { points[i].x = Double(i)}print("Structs: \\(CFAbsoluteTimeGetCurrent() - start) Sekunden")
start = CFAbsoluteTimeGetCurrent()var pointClasses = [PointClass]()for i in 0..<count { let p = PointClass(x: Double(i), y: 0) pointClasses.append(p)}print("Classes: \\(CFAbsoluteTimeGetCurrent() - start) Sekunden")2. Optimierung der Arbeit mit Multithreading (GCD)
Grand Central Dispatch (GCD) ist ein leistungsstarkes Werkzeug für die parallele Ausführung von Aufgaben. Eine falsche Verwendung kann zu Blockaden (deadlocks) und Leistungseinbußen führen.
2.1. Verwenden Sie die richtigen Warteschlangen
Verwenden Sie für Hintergrundaufgaben globale Warteschlangen mit Quality of Service (QoS):
.userInteractive— für Aufgaben, die eine sofortige Reaktion erfordern (z. B. Animationen)..userInitiated— für Aufgaben, die vom Benutzer initiiert wurden (z. B. Daten laden)..utility— für langlaufende Aufgaben (z. B. Dateiverarbeitung)..background— für Aufgaben, die die Benutzeroberfläche nicht beeinflussen (z. B. Synchronisation).
DispatchQueue.global(qos: .userInitiated).async { // Schwere Aufgabe let result = performHeavyCalculation() DispatchQueue.main.async { // UI-Update auf dem Hauptthread self.updateUI(with: result) }}2.2. Vermeiden Sie die Blockierung des Hauptthreads
Alle Operationen, die mit der Benutzeroberfläche zu tun haben, müssen auf dem Hauptthread ausgeführt werden. Verlagern Sie schwere Berechnungen und Netzwerk ```