Ein Absturz, dreimal reproduziert, einmal repariert
Szene 3 von 13
Bevor Build 9 überhaupt infrage kam, stürzte Build 8 beim Öffnen von drei Lernwegen ab. Die Reparatur folgte derselben Regel wie jede Handlung an diesem Tag: erst die Ursache beweisen, dann reparieren, dann den Beweis wiederholen.
Erklärung
„Es stürzt manchmal ab“ ist keine Ursache. Die erste Handlung war deshalb, den Absturz dreimal hintereinander zuverlässig auszulösen und genau zu protokollieren, wo im Code er geschah. Die Ursache war ein einzelner Formatstring: eine Textvorlage erwartete ein Objekt, der Platzhalter `%@` erhielt aber eine Ganzzahl — und die Laufzeit versuchte, diese Zahl wie eine Speicheradresse zu lesen, was zum Absturz führte. Die Korrektur war eine einzige geänderte Zeile pro Sprache: dieselbe Textvorlage, aber mit dem richtigen Platzhalter für eine Zahl, `%lld`. Damit war die Reparatur aber nicht automatisch bewiesen — derselbe dreifache Reproduktionsversuch lief nach der Korrektur erneut, diesmal ohne Absturz, und eine zusätzliche automatisierte Prüfung wurde geschrieben. Der Beleg zeigt alle drei Schritte getrennt: Reproduktion, Korrektur, erneuter Beweis.
Beweis statt Vermutung
- Reproduzieren
- Dreimal hintereinander zuverlässig auslösen und den Ort im Code festhalten.
- Ursache benennen
- `%@` (Objekt) wird mit einer Ganzzahl gefüttert → Laufzeit liest eine Adresse.
- Beweis wiederholen
- Derselbe dreifache Versuch nach der Korrektur, diesmal ohne Absturz.
git show --stat 9952c2ff # Ursache: dreifach reproduziert
git show 58069ab2 -- '*.xcstrings' # Korrektur: %@ -> %lld
git show --stat 28e9ac1f # Beweis: erneut geprüft, kein Absturz
Denkpause
Die Korrektur betraf nur eine Textvorlage pro Sprache. Warum genügt das nicht als abgeschlossene Reparatur?
Weil der Absturz schon behoben wurde, sobald der Code geändert ist.
Der Code zu ändern ist eine Behauptung; der erneute Lauf ist der Beweis.
Weil die dreifache Reproduktion erst erneut ohne Absturz durchlaufen muss, bevor die Reparatur bewiesen ist.
Richtig. Reparatur-Behauptung und Reparatur-Beweis sind zwei verschiedene Schritte.
Weil die Textvorlage gelöscht gehört.
Die Vorlage wird nicht gelöscht, sondern korrigiert.
Belege
QA-Bericht · Ursache benannt · docs(leana): IOS-CRASH-01-LERNWEGE reproduced 3/3 — reader.pageNumber 'Seite %@' object placeholder fed Int -> SIGSEGV (root cause)
2026-09-23 · docs/lernbegleiter/engineering/ios-qa-crash-01-lernwege-2026-09-23_05-27-41.md · 9952c2ff1abcc084460296e3700c3c27be8ff16b
## Root cause (source-verified)
`ReaderView.SourcesSection.body` (ReaderView.swift:479-480):
```swift
if let page = ref.page { // ContentSourceRef.page: Int? (ContentRepository.swift:516)
Text(L.string("reader.pageNumber", page))
}
```
`L.string(_:_:)` (Localization.swift:139) runs `String(format: format, locale:, arguments: args)` with the resolved catalog string. The German `reader.pageNumber` value is **`"Seite %@"`** (`Localizable.xcstrings`), i.e. an object placeholder, but `page` is an `Int`. `String(format:)` dereferences the integer as an object pointer → `objc_opt_respondsToSelector(0x<page>)` → SIGSEGV. Topics whose content source refs carry a page number (the first three Lernwege topics all do) crash; page-number-less topics do not. Safe sibling usage for contrast: `SessionView.swift:697` uses interpolation `" · S. \($0)"` instead of `%@`.
Suggested fix (engineering): make the placeholder numeric (`"Seite %lld"`) or pass a value the format expects (`L.string("reader.pageNumber", NSNumber(value: page))` / `String(page)` / interpolation). Same audit for any other `%@`-format key fed a non-object (`ExamView.swift:619` uses `citation.page` with a similar `L.string` call — check its catalog placeholder too).Code · Originalauszug · Formatplatzhalter korrigiert · fix(ios): IOS-CRASH-01 reader.pageNumber 'Seite %@' object placeholder -> '%lld' numeric (SIGSEGV on Int deref); add CrashFixRuntimeTests
2026-09-23 · ios/Lernvisite/Resources/Localizable.xcstrings · 58069ab216903a66ae32c80ab9dbaf4f12af6d82
"reader.pageNumber": {
"localizations": {
"de": {
"stringUnit": {
"state": "translated",
"value": "Seite %lld"
}
},
"en": {
"stringUnit": {
"state": "translated",
"value": "Page %lld"
}
},
"hu": {
"stringUnit": {
"state": "translated",
"value": "%lld . oldal"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "第 %lld 页"
}
}
}
},QA-Bericht · Beweis nach Korrektur · docs(leana): IOS-CRASH-01 corrected-candidate VERIFIED PASS (independent QA, 3 topics no-crash + 4-locale page numbers)
2026-09-23 · docs/lernbegleiter/engineering/ios-qa-crash-01-fix-verify-2026-09-23_06-16-54.md · 28e9ac1fb1207f210ee5d7c5f22ee66c607f0050
## Verdict — PASS The corrected candidate renders the first three Lernwege topics with the page number and **does not crash**; navigation/back-state and four-language localization all hold.
Mit meinem Konto im Hörsaal öffnen →