Caching in Swift (iOS/macOS): von In-Memory bis Redis
In der Entwicklung für iOS und macOS ist Caching ein zentrales Werkzeug, um die Leistung von Anwendungen zu beschleunigen, die Serverlast zu reduzieren und die Benutzererfahrung zu verbessern. In diesem Artikel betrachten wir die wichtigsten Ansätze zum Caching in Swift: vom einfachen NSCache bis hin zu professionellen Lösungen auf Basis von Redis und SQLite. Jede Methode hat ihren eigenen Anwendungsbereich, und die richtige Wahl hängt vom Datentyp, der Datenmenge und den Anforderungen an die Persistenz ab.
1. NSCache — integriertes In-Memory-Caching
NSCache ist ein leichter, threadsicherer Cache, der in Foundation integriert ist. Er gibt automatisch Speicher frei, wenn Ressourcen knapp werden, was ihn ideal für das Caching von Bildern, API-Daten und anderen temporären Objekten macht.
import Foundation
class ImageCache { private let cache = NSCache<NSString, UIImage>() func getImage(forKey key: String) -> UIImage? { return cache.object(forKey: key as NSString) } func setImage(_ image: UIImage, forKey key: String) { cache.setObject(image, forKey: key as NSString) } func removeImage(forKey key: String) { cache.removeObject(forKey: key as NSString) }}Vorteile:
- Keine Konfiguration erforderlich — funktioniert sofort.
- Verwaltet den Speicher automatisch (entfernt Objekte bei
didReceiveMemoryWarning). - Threadsicher.
Nachteile:
- Daten gehen beim Neustart der App verloren.
- Nicht geeignet für große Datenmengen (durch RAM begrenzt).
2. Core Data als persistenter Cache
Core Data wird oft nicht nur als ORM, sondern auch als Cache für strukturierte Daten verwendet. Dies ist praktisch, wenn komplexe Objekte mit Beziehungen gespeichert und gefiltert werden müssen.
import CoreData
class CoreDataCache { private let context: NSManagedObjectContext init(context: NSManagedObjectContext) { self.context = context } func cacheResponse(_ data: Data, forKey key: String) { let cached = CachedResponse(context: context) cached.key = key cached.data = data cached.timestamp = Date() try? context.save() } func getCachedResponse(forKey key: String) -> Data? { let fetchRequest: NSFetchRequest<CachedResponse> = CachedResponse.fetchRequest() fetchRequest.predicate = NSPredicate(format: "key == %@", key) fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: false)] fetchRequest.fetchLimit = 1 guard let result = try? context.fetch(fetchRequest).first else { return nil } return result.data }}Wann verwenden:
- Daten müssen zwischen Sitzungen erhalten bleiben.
- Komplexe Filterung erforderlich (z. B. Textsuche).
- Mäßige Datenmenge (bis zu mehreren hunderttausend Einträgen).
3. Redis — Server-seitiges Caching für Swift
Redis ist ein leistungsstarker In-Memory-Speicher, der über das Netzwerk arbeitet. Im Kontext von Swift (iOS/macOS) wird Redis meist serverseitig (Vapor, Kitura) zum Caching von Sitzungen, Ergebnissen komplexer Abfragen und Aufgabenwarteschlangen verwendet. Es gibt jedoch Client-Bibliotheken, die eine direkte Verbindung zu Redis aus einer mobilen App heraus ermöglichen (z. B. über RediStack).
import RediStack
final class RedisCache { private let connection: RedisConnection init(host: String, port: Int = 6379) async throws { self.connection = try await RedisConnection.connect( to: .init(hostname: host, port: port) ) }