← Alle Beitrage

MetricKit neu aufgebaut: zustandsbewusste Telemetrie in iOS 27

Apples WWDC-2026-Demo-App meldete eine Scroll-Hitch-Rate von 15 Millisekunden pro Sekunde, gemittelt über einen ganzen Nutzungstag. Nach Tab 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, wie iOS 27 diese Lücke schließt: ein grundlegender Neuaufbau der API-Oberfläche des Frameworks sowie ein neues Begleit-Framework, StateReporting, das gesamtheitliche Feld-Metriken der App 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 aufgebaut, mit einer kontextreichen und ausdrucksstarken, modernen Swift-First-API”, und jede neue Fähigkeit in der Session ist exklusiv den neuen APIs vorbehalten.1
  • Der Einstiegspunkt ist die Klasse MetricManager. Apps warten beim Start auf die asynchronen Streams metricReports und diagnosticReports, und beide Berichtstypen sind Codable, sodass ein JSONEncoder sie direkt an Ihren Analyse-Server schickt.1
  • Berichte sind strukturiert: intervalEntries enthalten einen Eintrag für den ganzen Tag sowie kleinere Aufschlüsselungen, organisiert in Metrikgruppen wie .cpu, .memory, .display und .gpu, bis hinunter zu einzelnen Werten wie peakMemory.1
  • Neue Daten in iOS 27: eine Metal-Bildwiederholrate-Metrik für die Render-Performance, Speicherausnahme-Diagnosen für Beendigungen wegen Speicherlimit-Überschreitung und eine Absturz-category, die einzelne Absturzdiagnosen mit Ihren Metrik-Trends verknüpft.1
  • Das herausragende Feature ist das StateReporting-Framework: Melden Sie den Zustand, in dem sich Ihre App befindet (aktiver Tab, Experiment-Arm, View-Konfiguration), und MetricKit aggregiert die Metriken pro Zustand und ersetzt eine einzige gemittelte Zahl durch eine Aufschlüsselung pro Bildschirm.1

Von Grund auf neu aufgebaut

Ansehen: Meet the new MetricKit (WWDC26)

Yonni, eine Ingenieurin im MetricKit-Team, stellt den iOS-27-Neuaufbau 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 Codepfad ein Problem verursacht hat.1 Geändert hat sich alles daran, wie Sie diese Daten erhalten. Die Session formuliert es unmissverständlich: In iOS 27 wurde das Framework „von Grund auf neu aufgebaut, mit einer kontextreichen und ausdrucksstarken, modernen Swift-First-API”, und „alle Fortschritte, die ich heute bespreche, sind exklusiv diesem neuen Satz an 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: Richten Sie das Ganze beim App-Start ein, „um Datenverluste 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 einem Detached Task oder einer dedizierten Service-Klasse auszuführen, sobald die App startet.1

Die Session zeigt den Code auf Folien, daher sind die folgenden Snippets veranschaulichende 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, mit undurchsichtigen Payload-Daten zu hantieren. 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 möchten, ist der Bericht vollständig strukturiert. Sie iterieren durch intervalEntries, die „einen über den ganzen Tag aggregierten Eintrag sowie kleinere Aufschlüsselungsfenster, sofern verfügbar” enthalten, typischerweise jeweils einige Stunden lang und nur dann vorhanden, wenn Metriken für sie existieren.1 Innerhalb jedes Intervalls sind die Metriken in Metrikgruppen organisiert, wobei „jede Gruppe einen Aspekt des Systems repräsentiert, Dinge wie .cpu, .memory, .display und .gpu”.1 Filtern Sie zu der Gruppe herunter, die Sie interessiert (das Beispiel der Session ruft memoryMetrics ab), und schalten Sie dann über die Metrik-Fälle, um zu einem einzelnen Wert wie peakMemory zu gelangen.1

Auch der Metrik-Katalog wächst in iOS 27. Neben Histogrammen der Startzeit (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-Bildwiederholrate-Metrik hinzu. Die Session bezeichnet die Bildwiederholrate als „eine Schlüsselmetrik, mit der Spieleentwickler die Render-Performance verstehen”, und verweist für die Optimierungsseite auf „Find and fix performance issues in your Metal game”.1

Diagnosen: Backtraces, Speicherausnahmen und Absturzkategorien

Metriken sagen Ihnen, dass etwas zurückging; Diagnosen sagen Ihnen, wo. Wenn etwas schiefgeht, etwa ein Absturz oder ein Hang, „erfasst das System eine Diagnose auf dem Gerät”, und ein Diagnosebericht „bündelt die Details und liefert sie über MetricKit sofort an Ihre App”.1 Viele Diagnosen enthalten Backtraces, die den exakten Aufrufstapel zum Zeitpunkt des Ereignisses zeigen. Im Durchgang der Session beginnt der symbolisierte Backtrace beim Thread-Start im Systemcode, geht in die App über und stoppt bei der Funktion submitReport() der App, die den Fehlerpunkt markiert und die Stelle, an der eine Korrektur ansetzen sollte.1

Absturzdiagnosen tragen einen Backtrace, den Beendigungsgrund und einen Ausnahmetyp. Neu in iOS 27 zeigt eine Beendigungs-category „an, wie jeder Absturz in den Metriken verbucht wurde”, sodass „Sie, wenn abnormale Beendigungen ansteigen, diese direkt mit einzelnen Diagnosen korrelieren können”.1 Die Metrik-Zeile auf Ihrem Dashboard und die einzelnen Absturzberichte dahinter teilen sich endlich einen Schlüssel.

iOS 27 fügt außerdem Speicherausnahme-Diagnosen hinzu: „Wenn Ihre App oder Erweiterung wegen Überschreitung ihres Speicherlimits beendet wird, erhalten Sie mehr Einblick in das, was passiert ist.”1 Erweiterungen sind ausdrücklich im Umfang enthalten, was für alle wichtig ist, die Speicher-Kills von Widgets oder Erweiterungen aus der Ferne debuggen.

Der Konsum spiegelt die Metrik-Seite wider. Sie warten auf Ihrer MetricManager-Instanz auf diagnosticReports, wiederum ab App-Start in einem Detached Task oder einer 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 Absturz-Fall liefert den Backtrace, den Grund und die category, während ein Hang-Fall zu einer anderen Verarbeitung weitergeleitet 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 bisher beschreibt weiterhin gesamtheitliche App-Telemetrie, und gesamtheitliche Telemetrie hat eine Obergrenze. Die Spesenabrechnungs-App der Session macht das Problem greifbar. Die App gliedert ihre Funktionen in einen Reports-Tab und einen Spending-Tab. Über einen Tag hinweg meldet MetricKit 4,5 Sekunden Gesamt-Hitch-Zeit über 5 Minuten Scrollen: eine Hitch-Rate von 15 ms/s. Diese Zahl ist jedoch „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 entfernt 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 Merkmale aggregieren kann”.1 Während die Nutzer 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 Neuaufbau rechtfertigt. Statt einer einzigen gemittelten Zahl von 15 ms/s treffen die Metriken pro Zustand ein: Der Spending-Tab scrollte „unglaublich flüssig” mit 1 ms/s, während der Reports-Tab „auf 71 ms/s hochschnellte”.1 Die Session zieht den Schluss, den die gemittelte Zahl niemals stützen könnte: „Der Spending-Tab läuft großartig! Aber der Reports-Tab erlebt kritische Unterbrechungen, und genau dorthin sollte sich Ihr Optimierungsaufwand richten.”1 Aus einer Zahl wurde ein Urteil und ein Arbeitsauftrag.

Zustände folgen einem Übergangsmodell, nicht einer Klammerung. „Es gibt keine Start- oder End-Paare – die App meldet zu jedem Zeitpunkt die Bedingung, in der sie sich 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 bezogen, die „eine Funktion oder einen Bereich einer App beschreibt”. Eine Domain kann jeweils nur einen aktiven Zustand halten, und separate Domains lassen mehrere Zustände gleichzeitig in Bearbeitung sein.1 Das Beispiel der Session ist ein A/B-Experiment: Mit eingeschalteter experimenteller Änderung werden Ausgaben in kleinen Stapeln aus der Datenbank abgerufen, ausgeschaltet in größeren Stapeln. Den Tab-Zustand und den Stapelgrößen-Zustand in separate Domains zu legen bedeutet, dass „MetricKit separate Metriken für jeden Tab und jede Stapelgröße liefert”.1 Telemetrie pro Bildschirm und Experiment-Auswertungen aus derselben Pipeline, im Feld.

Die Einführung umfasst in der Session drei Schritte: 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 in jeden Zustand eintritt, etwa den Übergang in einen Zustand, der durch den String „Reports” identifiziert wird.1 Für eine feinere Granularität definieren Sie Ihr eigenes Struct mit dem Makro ReportableMetadata, erstellen einen StateReporter mit diesem Metadaten-Typ und melden Übergänge sowohl mit dem Label als auch mit Ihrem eigenen Typ. Das ViewConfiguration-Beispiel der Session trägt einen listSize-Wert und die Information, ob die Liste sortiert ist.1 Nochmals: Die Session zeigt diesen Ablauf auf Folien ohne vollständige Signaturen, behandeln Sie die Form daher als etwas, das in der Dokumentation zu bestätigen ist, nicht als zu kopierende Syntax.

Auf der Empfängerseite 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, von denen jeder „Metrikwerte enthält, 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 stellt sowohl State-Entries als auch Interval-Entries „gruppiert nach jeder Domain und jedem Zustand, der im Bericht existiert” dar.1

Best Practices und wo Sie anfangen

Die Session schließt mit Empfehlungen, die sich wie hart erkämpfte Ratschläge zum Schema-Design lesen. Domains sollten eng auf einen App-Bereich begrenzt sein. Zustandsübergänge „sollten stabile, bedeutsame Phasen repräsentieren, keine flüchtigen UI-Ereignisse”.1 Gestalten Sie jeden Zustand so, dass der Zustand allein Ihnen genügend Informationen gibt, um die Korrektur gezielt anzusetzen, wenn eine Regression auftritt. 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 es gibt Obergrenzen für die Anzahl der Zustände, 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 Erfassungsseite ist nur die Hälfte des Systems. Die Session ist direkt: „Metriken über alle Geräte hinweg zu analysieren ist ein Data-Science-Problem”: Sie richten einen Server ein, 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 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 aufgebaut. Der Einstiegspunkt ist die neue Klasse MetricManager; Metrik- und Diagnose-Berichte treffen als awaitable asynchrone Streams ein (metricReports, diagnosticReports); Berichte sind Codable für die direkte JSON-Kodierung; und die Struktur ist im Code über intervalEntries und Metrikgruppen navigierbar. iOS 27 fügt außerdem eine Metal-Bildwiederholrate-Metrik, Speicherausnahme-Diagnosen, eine Absturz-category, die Absturzdiagnosen 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, in den sie wechselt, innerhalb einer von Ihnen definierten Domain. MetricKit verfolgt, wie lange die App in jedem Zustand verbleibt, und aggregiert die Metrikwerte über die dort verbrachte Zeit. Es gibt keine Start-/End-Paare; die App meldet einfach zu jedem Zeitpunkt die Bedingung, in der sie sich befindet. Jeder Zustand erhält dann seinen eigenen StateEntry im Metrik-Bericht.1

Kann ich mehr als eine Dimension auf einmal verfolgen, etwa Bildschirm und Experiment-Arm?

Ja. Jede Domain kann jeweils einen aktiven Zustand halten, aber separate Domains laufen gleichzeitig. Die Spesen-App der Session legt den aktiven Tab in eine Domain und ein Datenbank-Stapelgrößen-Experiment in eine andere, und MetricKit liefert separate Metriken für jeden Tab und jede Stapelgröße.1

Sollte ich jedes UI-Ereignis als Zustand melden?

Nein. Die Session empfiehlt Zustände, die stabile, bedeutsame Phasen repräsentieren statt flüchtiger UI-Ereignisse, eng auf einen App-Bereich begrenzte Domains und insgesamt Zurückhaltung: Zu viele Zustände erschweren die Interpretation der Daten, und das System erlegt Obergrenzen für die Anzahl der Zustände auf, 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?

Die Empfehlung 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 in diesem Jahr die Feld-Hälfte einer zweiteiligen Geschichte: Instruments zeigt Ihnen das Hitch im Labor, und das zustandsbewusste MetricKit sagt Ihnen, welche Bildschirme bei echten Nutzern ruckeln – von der Laborseite aus behandelt in Instruments 27 und App-Reaktionsfähigkeit. Die Render-Arbeit, die einen 71-ms/s-Tab tatsächlich repariert, steht in SwiftUI-Performance und Interop in iOS 27. Und der Grund, warum gemittelte Durchschnitte überhaupt in die Irre führen, ist das Thema von dem Performance-Blindfleck. Der vollständige Serien-Hub ist die Apple Ecosystem Series.

References


  1. Apple, WWDC 2026 session 222, Meet the new MetricKit. Source for the iOS 27 ground-up rebuild and Swift-first API framing, the MetricManager entry point and the metricReports / diagnosticReports async streams, Codable reports and JSONEncoder usage, intervalEntries and metric groups (.cpu, .memory, .display, .gpu, peakMemory), the Metal frame rate metric, memory exception diagnostics, the crash termination category, the submitReport() backtrace walkthrough, the StateReporting framework (domains, transition model, StateReporter, ReportableMetadata, stateEntries, byStateReportingDomain via encodingFormatKey), the expense-app demo numbers (15 ms/s blended; 1 ms/s Spending tab versus 71 ms/s Reports tab), the state best practices and Points of Interest validation, and the guidance to migrate from MXMetricManager to MetricManager

Verwandte Beiträge

Was Instruments 27 für die App-Reaktionsfähigkeit Neues bietet

Instruments 27 ergänzt Top Functions, Run Comparisons, ein Swift-executors-Instrument und ein neues Inspector-Panel, um …

11 Min. Lesezeit

SwiftUI-Performance und -Interop in iOS 27

Wie SwiftUI in iOS 27 das Scrollen in Lazy Stacks, GPU-Shader-Effekte und die Interop mit AppKit/UIKit handhabt – auf Gr…

14 Min. Lesezeit

Von 76 auf 100: Ein perfekter Lighthouse-Score

Wie eine persönliche Portfolio-Website von einem mobilen Lighthouse-Performance-Score von 76 mit 0,493 CLS zu einem perf…

6 Min. Lesezeit