Ein Vorschaubild in einer Liste lädt beim ersten Mal normal und erscheint beim zweiten Mal fast sofort. Daraus lässt sich leicht schließen, der Cache funktioniere. Möglicherweise hält die Ansicht aber nur noch das Bildobjekt im Speicher. Um den HTTP-Cache unter iOS zu prüfen, muss sichtbar sein, was beim Server ankommt: Beim ersten Abruf sollte er die Bilddaten zurückgeben; ist die Antwort nicht mehr frisch, sollte der Client sie per ETag erneut validieren. Das Lesen ohne Netzwerkverbindung ist ein eigener Test – ein schneller erneuter Bildaufbau ersetzt ihn nicht.
Testbedingungen festlegen
Testserver und iOS-Simulator laufen auf demselben Remote-Mac. Greife aus dem Simulator über localhost zu, damit Schwankungen einer regionsübergreifenden Verbindung die Cache-Bewertung nicht verfälschen. Verwende eine kleine PNG-Datei, lege sie im aktuellen Arbeitsverzeichnis ab und nenne sie thumb.png. Ändere während dieses Tests weder URL noch Account oder Bilddecoder.
Geprüft werden genau drei beobachtbare Ergebnisse:
| Szenario | Was der Server sehen sollte | Was die App erhalten sollte |
|---|---|---|
| Erster Abruf | Kein If-None-Match; Antwort 200 |
Bilddaten |
| Erneuter Abruf | Ein passender ETag; Antwort 304 | Das über den Cache erneut validierte Bild |
| Explizites Offline-Lesen | Keine neue Anfrage | Das gespeicherte Bild oder ein eindeutiger Cache-Miss |
Eine 304-Antwort enthält keine Bilddaten. Die App kann das Bild trotzdem anzeigen, weil der Client die gespeicherten Daten mit dem Ergebnis der erneuten Validierung kombiniert. Aus „Die UI hat ein Bild erhalten“ darf nicht „Der Server hat das Bild erneut gesendet“ werden.
Einen Server mit Protokollierung bedingter Anfragen starten
Speichere das folgende Skript im Verzeichnis der Bilddatei als fixture.py. Es lauscht nur auf der lokalen Loopback-Adresse; der Testport ist nicht von außen erreichbar. max-age=0 erzwingt bei späteren regulären Anfragen eine erneute Validierung. Ein fester ETag macht den Ablauf leicht nachvollziehbar.
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
BODY = Path("thumb.png").read_bytes()
TAG = '"thumb-v1"'
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/thumb":
self.send_error(404)
return
matched = self.headers.get("If-None-Match") == TAG
status = 304 if matched else 200
print(f"If-None-Match={self.headers.get('If-None-Match')!r} status={status}", flush=True)
self.send_response(status)
self.send_header("ETag", TAG)
self.send_header("Cache-Control", "public, max-age=0")
if not matched:
self.send_header("Content-Type", "image/png")
self.send_header("Content-Length", str(len(BODY)))
self.end_headers()
if not matched:
self.wfile.write(BODY)
HTTPServer(("127.0.0.1", 8765), Handler).serve_forever()
Starte python3 fixture.py. Prüfe dann in einem anderen Terminal mit curl -si http://127.0.0.1:8765/thumb -o /dev/null, ob eine 200-Antwort zurückkommt, und führe anschließend Folgendes aus:
curl -si -H 'If-None-Match: "thumb-v1"' \
http://127.0.0.1:8765/thumb -o /dev/null
Im Serverprotokoll sollten nacheinander 200 und 304 stehen. Dieser Schritt bestätigt nur, dass der Testserver wie erwartet funktioniert. Er beweist nicht, dass iOS automatisch bedingte Anfragen sendet.
Simulatoranfragen mit derselben Session prüfen
Verwende für das Test-Target eine eigene URLSessionConfiguration.default mit einem URLCache, der ausreichend Arbeitsspeicher bereitstellt. Die Anfragerichtlinie bleibt .useProtocolCachePolicy. Rufe dieselbe URL zweimal über dieselbe Session ab. Warte jeweils auf den Abschluss des Tasks und prüfe, ob das Ergebnis ein decodierbares PNG ist. Im Serverprotokoll sollte der erste Abruf mit 200 enden. Falls der zweite Abruf den Server erreicht, sollte er If-None-Match enthalten und eine 304-Antwort erhalten.
let configuration = URLSessionConfiguration.default
configuration.urlCache = URLCache(
memoryCapacity: 8 * 1024 * 1024,
diskCapacity: 0
)
configuration.requestCachePolicy = .useProtocolCachePolicy
let session = URLSession(configuration: configuration)
let url = URL(string: "http://localhost:8765/thumb")!
Beide Bildanfragen der App müssen diese session verwenden; erstelle nicht für jede Anfrage eine neue Konfiguration. Falls die Transportsicherheitsrichtlinie lokales HTTP im Simulator-Test-Target blockiert, aktiviere eine Ausnahme für das lokale Netzwerk ausschließlich in der Konfiguration dieses Targets. Übernimm die Entwicklungsausnahme nicht in die produktive App. Fehlt die zweite Anfrage vollständig im Serverprotokoll, prüfe zuerst, ob ein bereits im Speicher befindliches Bild wiederverwendet wurde und ob die App tatsächlich einen zweiten Ladevorgang gestartet hat. Untersuche erst danach die Cache-Richtlinie. An der Laufzeit allein lassen sich diese Fälle nicht unterscheiden.
ETag bei geändertem Bild prüfen
Ändere TAG auf dem Server zu '"thumb-v2"', ersetze zugleich thumb.png, starte den Server neu und rufe das Bild erneut ab. Der alte ETag sollte nicht mehr passen: Die neue Antwort sollte 200 lauten, und die App sollte das neue Bild erhalten. In einem echten Projekt muss sich der ETag mit der Inhaltsversion ändern. Wird eine Datei ersetzt, ihre alte Kennung aber beibehalten, kann die erneute Validierung fälschlich das alte Bild erhalten.
Offline-Lesen getrennt testen
Schließe zunächst online einen Abruf mit 200-Antwort ab und prüfe, ob die Antwort gespeichert werden darf. Stoppe danach den Testserver. Erstelle für dieselbe URL eine Anfrage mit der Richtlinie .returnCacheDataDontLoad und starte den Task weiterhin über die Session, die den ursprünglichen Cache hält. Erfolg bedeutet, dass dieser Abruf aus dem Cache bedient wurde. Halte einen Fehlschlag als Cache-Miss fest, statt ihn automatisch zum Serverfehler zu erklären. Prüfe nach dem Test das Serverprotokoll: Die Offline-Anfrage darf weder vor noch nach dem Stoppen des Servers einen neuen Eintrag verursacht haben.
Die Offline-Richtlinie ist eine bewusste Entscheidung der App. Sie bedeutet nicht, dass eine Anfrage mit der Standardrichtlinie bei fehlender Netzwerkverbindung zwangsläufig auf ein altes Bild zurückgreift. Cache-Kapazität, Bereinigungen durch das System und Antwort-Header beeinflussen die Trefferquote. Die Oberfläche sollte bei einem Cache-Miss einen Platzhalter anzeigen und nach Wiederherstellung der Verbindung einen erneuten Versuch ermöglichen – statt anzunehmen, dass ein früher geöffnetes Bild immer verfügbar ist.
Fehlschlüsse untersuchen und Prüfergebnisse festhalten
Notiere für jeden Durchlauf die Test-URL, den ETag, die Cache-Header der Antwort, die Statusfolge im Serverprotokoll und die Bildversion, die die App schließlich anzeigt. Bei 200→200 prüfe zuerst, ob die Antwort cachefähig ist und ob beide Anfragen dieselbe URL und denselben Cache nutzen. Meldet der Server 304, während die UI weiterhin das alte Bild zeigt, prüfe, ob nach der Verarbeitung der Antwort ein altes Objekt aus der Ansichtsebene das Ergebnis überschreibt. Kommt auch nach einer Bildänderung noch 304 zurück, kontrolliere zuerst, ob die Kennung auf dem Server tatsächlich aktualisiert wurde.
Wiederhole zum Schluss den ersten Test mit einer frisch installierten Simulator-App, damit Caches aus früheren Versuchen das Ergebnis nicht beeinflussen. So wird aus „Das Bild schien schnell zu laden“ eine überprüfbare Aufzeichnung von vier Ergebnissen: 200, 304, Offline-Treffer und Cache-Miss. Nach Änderungen am Bilddienst oder an der Cache-Richtlinie des Clients kann das Team den Test damit erneut durchführen.
Häufig gestellte Fragen
Wie lässt sich eine 304-Antwort sicher nachweisen?
Prüfen Sie im Serverprotokoll den Header If-None-Match und den Antwortstatus. Eine angezeigte Grafik allein ist kein Nachweis.
Warum fehlt ein zuvor geladenes Bild ohne Netz?
Der Eintrag kann verdrängt oder nicht speicherbar sein. Zudem liest eine normale Anfrage nicht zwingend ausschließlich aus dem Cache.
Ein Mac für Ihre nächste Remote-Entwicklung
Wählen Sie Modell und Standort passend zu Ihrem Vorhaben und verbinden Sie sich per Bildschirmfreigabe, VNC oder SSH. Preise und Verfügbarkeit sehen Sie aktuell in der Konsole.