MetricKit neu gebaut: Zustandsbewusste Telemetrie in iOS 27
Apples WWDC-2026-Demo-App meldete eine Scroll-Hitch-Rate von 15 Millisekunden pro Sekunde, gemittelt über einen ganzen Tag der Nutzung. Nach Tabs aufgeschlüsselt erzählten dieselben Daten eine völlig andere Geschichte: 1 ms/s auf dem einen Tab, 71 ms/s auf dem anderen.1 Ein Bildschirm war nahezu makellos; der andere erlebte, in den Worten der Session, „kritische Unterbrechungen”.1 Die gemittelte Zahl verbarg beide Tatsachen. Session 222, „Meet the new MetricKit”, erzählt die Geschichte, wie iOS 27 diese Lücke schließt: ein grundlegender Neubau der API-Oberfläche des Frameworks und ein neues begleitendes Framework, StateReporting, das gesamtanwendungsbezogene Feldmetriken in Metriken pro Zustand verwandelt. Feldtelemetrie kann endlich die Frage beantworten, die jeder Performance-Ingenieur zuerst stellt: Welcher Bildschirm ist langsam?
TL;DR
- In iOS 27 wurde MetricKit „von Grund auf neu gebaut, mit einer kontextreichen und ausdrucksstarken modernen Swift-first-API”, und jede neue Fähigkeit der Session ist exklusiv den neuen APIs vorbehalten.1
- Der Einstiegspunkt ist die Klasse
MetricManager. Apps warten beim Start auf die asynchronen StreamsmetricReportsunddiagnosticReports, und beide Berichtstypen sindCodable, sodass einJSONEncodersie direkt an Ihren Analytics-Server sendet.1 - Berichte sind strukturiert:
intervalEntriesenthalten einen Ganztageseintrag sowie kleinere Aufschlüsselungen, organisiert in Metrikgruppen wie.cpu,.memory,.displayund.gpu, bis hinunter zu einzelnen Werten wiepeakMemory.1 - Neue Daten in iOS 27: eine Metal-Bildraten-Metrik für die Render-Performance, Speicherausnahme-Diagnosen für Beendigungen wegen Speicherlimits und eine Crash-
category, die einzelne Crash-Diagnosen mit Ihren Metrik-Trends verknüpft.1 - Das Hauptfeature ist das
StateReporting-Framework: Melden Sie den Zustand, in dem sich Ihre App befindet (aktiver Tab, Experiment-Variante, View-Konfiguration), und MetricKit aggregiert Metriken pro Zustand, wodurch eine gemittelte Zahl durch eine Aufschlüsselung pro Bildschirm ersetzt wird.1
Von Grund auf neu gebaut
Yonni, ein Ingenieur im MetricKit-Team, stellt den iOS-27-Neubau ab 1:23 vor.
Die Aufgabe von MetricKit hat sich nicht geändert: Es ist „das Erfassungsstück” des Performance-Workflows und liefert zwei Arten von Daten. Metriken sagen Ihnen, ob sich ein Performance-Bereich insgesamt verbessert oder verschlechtert; Diagnosen sagen Ihnen, welcher Code-Pfad ein Problem verursacht hat.1 Was sich geändert hat, ist alles daran, wie Sie diese Daten empfangen. Die Session formuliert es unmissverständlich: In iOS 27 wurde das Framework „von Grund auf neu gebaut, mit einer kontextreichen und ausdrucksstarken modernen Swift-first-API”, und „alle Fortschritte, die ich heute bespreche, sind exklusiv diesem neuen Satz von APIs vorbehalten”.1
Der neue Einstiegspunkt ist die Klasse MetricManager. Statt einen Delegate zu registrieren und Payloads zu parsen, warten Sie über die Eigenschaft metricReports als asynchronen Stream auf Berichte. Zwei betriebliche Regeln stammen direkt aus der Session: Führen Sie die Einrichtung beim App-Start durch, „um Datenverlust durch verzögertes Abonnieren zu vermeiden”, und halten Sie MetricManager am Leben, „damit die Streams weiterhin Berichte liefern können, sobald nachfolgende Daten bereitstehen”.1 Apple empfiehlt, die Arbeit in einer detached Task oder einer dedizierten Service-Klasse auszuführen, sobald die App startet.1
Die Session präsentiert den Code auf Folien, daher sind die folgenden Snippets illustrative Aufruf-Formen, die ihrer Beschreibung entsprechen; bestätigen Sie die genauen Signaturen anhand von Apples Dokumentation, bevor Sie ausliefern.
// Illustrative call shape based on session 222; verify against the docs.
let manager = MetricManager()
Task.detached {
for await report in manager.metricReports {
// Encode and ship, or inspect specific groups.
}
}
Einen Bericht an Ihren Server zu senden, bedeutete früher den Umgang mit undurchsichtigen Payload-Daten. Jetzt sind MetricReport-Werte Codable: „Erstellen Sie einfach einen JSONEncoder und kodieren Sie den gesamten Bericht.”1 Wenn Sie statt des ganzen Dokuments einen bestimmten Wert wünschen, ist der Bericht vollständig strukturiert. Sie iterieren durch intervalEntries, die „einen ganztägig aggregierten Eintrag sowie kleinere Aufschlüsselungsfenster enthalten, sofern verfügbar”, typischerweise jeweils einige Stunden und nur dann vorhanden, wenn für sie Metriken existieren.1 Innerhalb jedes Intervalls sind Metriken in Metrikgruppen organisiert, wobei „jede Gruppe einen Aspekt des Systems repräsentiert, Dinge wie .cpu, .memory, .display und .gpu”.1 Filtern Sie auf die Gruppe herunter, die Sie interessiert (das Beispiel der Session ruft memoryMetrics ab), und schalten Sie dann über die Metrik-Fälle, um einen einzelnen Wert wie peakMemory zu erreichen.1
Auch der Metrik-Katalog wächst in iOS 27. Neben Startzeit-Histogrammen (das Beispiel der Session zeigt, dass die meisten Starts zwischen 510 und 540 Millisekunden liegen), Hangs, Animationsmetriken und Ressourcenverbrauch wie CPU, GPU, Festplattenschreibvorgängen und Netzwerkübertragungen fügt MetricKit eine Metal-Bildraten-Metrik hinzu. Die Session nennt die Bildrate „eine Schlüsselmetrik für Spieleentwickler, um die Render-Performance zu verstehen” und verweist auf „Find and fix performance issues in your Metal game” für die Optimierungsseite.1
Verlassen Sie sich auf die Startmetrik von MetricKit, statt den Start selbst zu instrumentieren. Apple misst die Startzeit vom Moment, in dem der Benutzer auf das App-Symbol tippt, bis zum ersten gezeichneten Frame, was geschieht, bevor Ihr Prozess überhaupt existiert.3 Ein selbst gebauter Timer kann erst starten, sobald Ihr Code läuft, verpasst also das Fenster vor main vollständig und unterschätzt den Start, den Ihre Benutzer tatsächlich erleben. Lesen Sie das Histogramm, das MetricKit liefert, statt einen Timer zu bauen, der den entscheidenden Teil nicht sehen kann.
Diagnosen: Backtraces, Speicherausnahmen und Crash-Kategorien
Metriken sagen Ihnen, dass etwas zurückgegangen ist; Diagnosen sagen Ihnen, wo. Wenn etwas schiefgeht, etwa ein Crash oder ein Hang, „erfasst das System eine Diagnose auf dem Gerät”, und ein Diagnosebericht „bündelt die Details und liefert sie sofort über MetricKit an Ihre App”.1 Viele Diagnosen enthalten Backtraces, die den genauen Call-Stack zum Zeitpunkt des Ereignisses zeigen. In der Durchgehensweise der Session beginnt der symbolisierte Backtrace beim Thread-Start im Systemcode, geht in die App über und endet bei der Funktion submitReport() der App, die den Fehlerpunkt und die Stelle markiert, an der eine Korrektur ansetzen sollte.1
Crash-Diagnosen tragen einen Backtrace, den Beendigungsgrund und einen Ausnahmetyp. Neu in iOS 27 zeigt eine Beendigungs-category „an, wie jeder Crash in den Metriken verbucht wurde”, sodass „Sie, wenn abnormale Beendigungen ansteigen, diese direkt mit einzelnen Diagnosen korrelieren können”.1 Die Metrik-Linie auf Ihrem Dashboard und die einzelnen Crash-Berichte dahinter teilen sich endlich einen Schlüssel.
iOS 27 fügt außerdem Speicherausnahme-Diagnosen hinzu: „Wenn Ihre App oder Extension wegen Überschreitung ihres Speicherlimits beendet wird, erhalten Sie mehr Einblick darüber, was passiert ist.”1 Extensions sind ausdrücklich im Geltungsbereich, was für alle wichtig ist, die Speicher-Kills von Widgets oder Extensions aus der Ferne debuggen.
Der Verbrauch spiegelt die Metrik-Seite wider. Sie warten auf diagnosticReports Ihrer MetricManager-Instanz, wiederum vom App-Start an in einer detached Task oder Service-Klasse, und DiagnosticReport-Werte sind Codable für dieselbe Encode-and-Ship-Pipeline.1 Da die Berichte strukturiert sind, können Sie über die Diagnose-Fälle schalten: Der Crash-Fall liefert den Backtrace, den Grund und die category, während ein Hang-Fall zu einer anderen Verarbeitung geleitet werden kann.1
// Illustrative call shape based on session 222; verify against the docs.
for await report in manager.diagnosticReports {
switch /* diagnostic case */ {
case /* crash */: break // backtrace, reason, category
case /* hang */: break // handle separately
default: break
}
}
StateReporting: von einer gemittelten Zahl zur Wahrheit pro Bildschirm
Alles oben beschreibt weiterhin gesamtanwendungsbezogene Telemetrie, und diese hat eine Obergrenze. Die Spesenabrechnungs-App der Session macht das Problem greifbar. Die App organisiert ihre Funktionen in einen Reports-Tab und einen Spending-Tab. Über einen Tag meldet MetricKit 4,5 Sekunden gesamte Hitch-Zeit über 5 Minuten Scrollen: eine Hitch-Rate von 15 ms/s. Aber diese Zahl ist „eine durchschnittliche Scroll-Hitch-Rate über die gesamte App-Nutzung, selbst wenn jemand zwischen dem Reports-Tab und dem Spending-Tab hin- und herwechselt”.1 Sie wissen, dass die App ruckelt. Sie wissen nicht, wo.
Das neue StateReporting-Framework beseitigt die Vermischung. Zustände sind „Informationen, die Sie definieren und die die Konfiguration oder das Verhalten Ihrer App beschreiben, sodass MetricKit Metriken als Funktion dieser Eigenschaften aggregieren kann”.1 Während Personen zwischen Tabs wechseln, meldet die App jeden Übergang, und MetricKit verschneidet diese Zustände mit Metrik- und Diagnosedaten.1
Der Ertrag in der Demo ist der Moment, der den Neubau rechtfertigt. Statt einer gemittelten Zahl von 15 ms/s treffen Metriken pro Zustand ein: Der Spending-Tab scrollte „unglaublich flüssig” bei 1 ms/s, während der Reports-Tab „auf 71 ms/s hochschoss”.1 Die Session zieht die Schlussfolgerung, die die gemittelte Zahl niemals stützen könnte: „Der Spending-Tab performt großartig! Aber der Reports-Tab erlebt kritische Unterbrechungen, und genau darauf sollte sich Ihr Optimierungsaufwand konzentrieren.”1 Aus einer Zahl wurden ein Urteil und ein Arbeitsauftrag.
Zustände folgen einem Übergangsmodell, keiner Klammerung. „Es gibt keine Start- oder End-Paare — die App meldet die Bedingung, in der sie sich zu einem bestimmten Zeitpunkt befindet”, und MetricKit verfolgt, wie lange die App in jedem Zustand verbleibt.1
Domains, Metadaten und Kodierung nach Zustand
Jeder Zustand ist auf eine Domain beschränkt, die „eine Funktion oder einen Bereich einer App beschreibt”. Eine Domain kann jeweils nur einen aktiven Zustand halten, und getrennte Domains lassen mehrere Zustände gleichzeitig in Bearbeitung sein.1 Das Beispiel der Session ist ein A/B-Experiment: Mit einer aktivierten experimentellen Änderung werden Spesen in kleinen Batches aus der Datenbank abgerufen; ohne sie in größeren Batches. Den Tab-Zustand und den Batch-Größen-Zustand in getrennte Domains zu legen bedeutet, dass „MetricKit getrennte Metriken für jeden Tab und jede Batch-Größe liefert”.1 Telemetrie pro Bildschirm und Experiment-Auswertungen aus derselben Pipeline, im Feld.
Die Einführung erfolgt in der Session in drei Schritten: Importieren Sie das StateReporting-Framework, erstellen Sie eine Domain („typischerweise ein Reverse-DNS-String”) und registrieren Sie sie, wenn Sie Ihre MetricManager-Instanz einrichten, und melden Sie dann Übergänge, sobald die App jeden Zustand betritt, etwa den Übergang zu einem Zustand, der durch den String „Reports” identifiziert wird.1 Für feinere Granularität definieren Sie Ihr eigenes Struct mit dem Makro ReportableMetadata, erstellen einen StateReporter mit diesem Metadaten-Typ und melden Übergänge mit sowohl dem Label als auch Ihrem benutzerdefinierten Typ. Das ViewConfiguration-Beispiel der Session trägt einen listSize-Wert und ob die Liste sortiert ist.1 Nochmals: Die Session zeigt diesen Ablauf auf Folien ohne vollständige Signaturen, behandeln Sie die Form also als etwas, das in der Dokumentation zu bestätigen ist, statt als zu kopierende Syntax.
Auf der empfangenden Seite erhält der Bericht eine zweite Achse. Bevor irgendwelche Zustände gemeldet werden, ist die Eigenschaft stateEntries Ihres Metrik-Berichts leer. Nach der Einführung trägt der Bericht StateEntry-Werte, die jeweils „Metrikwerte halten, die über die in diesem einzelnen Zustand verbrachte Zeit aggregiert sind”.1 Für die Server-Pipeline können Sie die kodierte Ausgabe nach Domain gruppieren: Setzen Sie den Schlüssel encodingFormatKey in der Eigenschaft userInfo Ihres JSONEncoder auf byStateReportingDomain, und der kodierte Bericht präsentiert sowohl State-Einträge als auch Intervall-Einträge, „gruppiert nach jeder Domain und jedem Zustand, der im Bericht existiert”.1
Best Practices und wo Sie anfangen
Die Session schließt mit Hinweisen, die sich wie schwer erarbeitete Ratschläge zum Schema-Design lesen. Domains sollten eng auf einen App-Bereich zugeschnitten sein. Zustandsübergänge „sollten stabile, bedeutsame Phasen repräsentieren, keine vorübergehenden UI-Ereignisse”.1 Gestalten Sie jeden Zustand so, dass bei einer Regression der Zustand allein Ihnen genug Information gibt, um die Korrektur anzusetzen. Und widerstehen Sie dem Drang, alles zu instrumentieren: „Zu viele Zustände können zu Daten führen, die zu granular sind, und können es tatsächlich erschweren, das Gesamtbild zu interpretieren”, und Obergrenzen für die Anzahl der Zustände existieren, um den Overhead zu minimieren (die Session nennt keine Zahl).1 Validieren Sie vor dem Ausliefern mit dem Points-of-Interest-Instrument, dass die gemeldeten Zustände Ihren Erwartungen entsprechen.1
Die Kardinalität ist dieselbe Falle von der Metadaten-Seite. Fassen Sie sich schnell ändernde Zustandswerte in grobe Kategorien (klein, mittel, groß) zusammen, statt exakte Zählwerte zu melden. Im Performance-Lab von Apples WWDC 2026, wo das Team Live-Fragen zur MetricKit-Einführung und zum umfassenderen Power-Workflow beantwortete (festgehalten in was Apples Performance-Team im WWDC26-Lab sagte), merkte das Team an, dass das Aufzeichnen von „1.000 gegenüber 1.001 Elementen” Kosten ohne Erkenntnisgewinn verursacht: Die beiden Werte landen im selben Performance-Regime, sodass ein eigener Zustand für jeden von ihnen Overhead und nichts sonst einbringt.4 Wählen Sie die Grenzen, die das Verhalten ändern, und fassen Sie alles dazwischen zusammen.
Die Erfassungsseite ist nur die Hälfte des Systems. Die Session ist direkt darin, dass „das Analysieren von Metriken über alle Geräte hinweg ein Data-Science-Problem ist”: Sie stellen einen Server bereit, der Berichte aufnimmt, aggregieren entlang der Dimensionen, die Sie interessieren, etablieren eine Baseline und überwachen auf Bewegung in beide Richtungen.1 Die Codable-Berichte und die byStateReportingDomain-Kodierung existieren, um genau diese Pipeline zu speisen.
Für bestehende Anwender ist die abschließende Anweisung explizit: „Wenn Sie die MXMetricManager-API verwenden, migrieren Sie zur neuen MetricManager-API, um all diese neuen Fähigkeiten zu nutzen.”1 Apples Dokumentation formalisiert diese Migration nun: MXMetricManager ist seit 27.0 als veraltet markiert, mit dem Hinweis „Use MetricManager instead”.2 Dieselbe gestaffelte Durchsetzung an der 27er-Grenze trat in diesem Zyklus auch anderswo auf, einschließlich Image Playgrounds ImageCreator-Veraltung in iOS 27, wo eine Veraltungswarnung beim öffentlichen Release einem harten Bruch weicht. Die neuen APIs sind der Ort, an dem jeder Fortschritt der Session lebt, und die Session präsentiert sie als „die Zukunft des Frameworks”.1
FAQ
Was hat sich in MetricKit in iOS 27 tatsächlich geändert?
Das Framework wurde mit einer modernen Swift-first-API neu gebaut. Der Einstiegspunkt ist die neue Klasse MetricManager; Metrik- und Diagnoseberichte treffen als awaitable asynchrone Streams ein (metricReports, diagnosticReports); Berichte sind Codable für direkte JSON-Kodierung; und die Struktur ist im Code über intervalEntries und Metrikgruppen navigierbar. iOS 27 fügt außerdem eine Metal-Bildraten-Metrik, Speicherausnahme-Diagnosen, eine Crash-category, die Crash-Diagnosen mit der Metrik-Verbuchung verknüpft, und das StateReporting-Framework für Metriken pro Zustand hinzu.1
Wie entscheidet StateReporting, welche Metriken zu welchem Zustand gehören?
Ihre App meldet Übergänge: den Zustand, zu dem sie wechselt, innerhalb einer von Ihnen definierten Domain. MetricKit verfolgt, wie lange die App in jedem Zustand verbleibt, und aggregiert Metrikwerte über die dort verbrachte Zeit. Es gibt keine Start-/End-Paare; die App meldet einfach die Bedingung, in der sie sich zu einem bestimmten Zeitpunkt befindet. Jeder Zustand erhält dann seinen eigenen StateEntry im Metrik-Bericht.1
Kann ich mehr als eine Dimension gleichzeitig verfolgen, etwa Bildschirm und Experiment-Variante?
Ja. Jede Domain kann jeweils einen aktiven Zustand halten, aber getrennte Domains laufen gleichzeitig. Die Spesen-App der Session legt den aktiven Tab in eine Domain und ein Datenbank-Batch-Größen-Experiment in eine andere, und MetricKit liefert getrennte Metriken für jeden Tab und jede Batch-Größe.1
Sollte ich jedes UI-Ereignis als Zustand melden?
Nein. Die Session empfiehlt Zustände, die stabile, bedeutsame Phasen statt vorübergehender UI-Ereignisse repräsentieren, Domains, die eng auf einen App-Bereich zugeschnitten sind, und Zurückhaltung insgesamt: Zu viele Zustände erschweren die Interpretation der Daten, und das System legt Obergrenzen für die Anzahl der Zustände fest, um den Overhead zu minimieren. Validieren Sie Ihre Zustände vor dem Ausliefern mit dem Points-of-Interest-Instrument.1
Muss ich von MXMetricManager weg?
Der Hinweis der Session lautet, von MXMetricManager zur neuen MetricManager-API zu migrieren, denn jede behandelte neue Fähigkeit (asynchrone Streams, Codable-Berichte, zustandsbewusste Metriken, die neuen Metrik- und Diagnosetypen) ist exklusiv dem neuen API-Satz vorbehalten.1
MetricKit ist die Feld-Hälfte einer zweiteiligen Geschichte in diesem Jahr: Instruments zeigt Ihnen das Ruckeln im Labor, und das zustandsbewusste MetricKit sagt Ihnen, welche Bildschirme bei echten Benutzern ruckeln, von der Laborseite behandelt in Instruments 27 und App-Reaktionsfähigkeit. Die Render-Arbeit, die einen Tab mit 71 ms/s tatsächlich behebt, lebt in SwiftUI-Performance und Interoperabilität in iOS 27. Und der Grund, warum gemittelte Durchschnittswerte überhaupt in die Irre führen, ist das Thema von dem Performance-Blindfleck. Der vollständige Serien-Hub ist die Apple Ecosystem Series.
Referenzen
-
Apple, WWDC 2026 session 222, Meet the new MetricKit. Quelle für den grundlegenden iOS-27-Neubau und die Swift-first-API-Rahmung, den
MetricManager-Einstiegspunkt und die asynchronen StreamsmetricReports/diagnosticReports,Codable-Berichte und die Verwendung vonJSONEncoder,intervalEntriesund Metrikgruppen (.cpu,.memory,.display,.gpu,peakMemory), die Metal-Bildraten-Metrik, Speicherausnahme-Diagnosen, die Crash-Beendigungs-category, diesubmitReport()-Backtrace-Durchgehensweise, dasStateReporting-Framework (Domains, Übergangsmodell,StateReporter,ReportableMetadata,stateEntries,byStateReportingDomainüberencodingFormatKey), die Demo-Zahlen der Spesen-App (15 ms/s gemittelt; 1 ms/s Spending-Tab gegenüber 71 ms/s Reports-Tab), die Best Practices für Zustände und die Points-of-Interest-Validierung sowie den Hinweis, vonMXMetricManagerzuMetricManagerzu migrieren. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple Developer Documentation:
MXMetricManager. Seit 27.0 als veraltet markiert, mit dem Hinweis „Use MetricManager instead.” ↩ -
Apple Developer Documentation: Reducing your app’s launch time. Die Startzeit wird vom Moment, in dem der Benutzer auf das App-Symbol tippt, bis zum ersten gezeichneten Frame gemessen, bevor der Prozess der App existiert. ↩
-
Apple, WWDC 2026 performance group lab, session 8003. Paraphrasiert aus einer lokal transkribierten Aufnahme; es ist kein offizielles Transkript veröffentlicht. Das Team riet dazu, sich schnell ändernde Zustands-Metadaten in grobe Kategorien zusammenzufassen, mit dem Hinweis, dass das Aufzeichnen von „1.000 gegenüber 1.001 Elementen” Kosten ohne Erkenntnisgewinn verursacht. ↩