App: NFC-Fehler kurz statt "Stack Error", Knopf weg nach Erfolg
Apples localizedDescription kam unveraendert durch und lieferte beim
Beschreiben von Tags wiederholt "Stack Error" - ein Text, der niemandem
sagt, was zu tun ist. Jetzt uebersetzt NFCDienst.kurz die CoreNFC-Codes
in kurze Meldungen ("Tag zu frueh entfernt.", "NFC gerade belegt."); ein
unbekannter Code behaelt seine Nummer, damit der fehlende Fall beim
naechsten Auftreten feststeht.
Die Meldung steht jetzt auch in Apples Systemblatt: im Fehlerfall wurde
die Sitzung wortlos beendet, deshalb las man sie erst danach in der App.
Nach einem erfolgreichen Schreibvorgang verschwinden Knopf und
Schreibschutz-Schalter - sie standen vorher weiter da und waren aktiv,
ein weiterer Tipp hat das Tag ein zweites Mal beschrieben. Stattdessen
steht dort jetzt "Fertig".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
04f8c1fccd
commit
8c752e3d1f
@@ -99,6 +99,48 @@ final class NFCDienst: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kurzfassung eines CoreNFC-Fehlers.
|
||||||
|
///
|
||||||
|
/// Apples ``localizedDescription`` ist hier unbrauchbar – sie liefert Dinge
|
||||||
|
/// wie „Stack Error", die niemandem sagen, was zu tun ist. Fast alle Faelle
|
||||||
|
/// sind voruebergehend: Tag zu frueh weg, Funkkontakt verloren, Stack belegt.
|
||||||
|
///
|
||||||
|
/// Ein unbekannter Code behaelt seine Nummer. Damit steht beim naechsten
|
||||||
|
/// Auftreten sofort fest, welcher Fall hier noch fehlt.
|
||||||
|
static func kurz(_ fehler: Error) -> String {
|
||||||
|
guard let code = (fehler as? NFCReaderError)?.code else {
|
||||||
|
return "Fehlgeschlagen."
|
||||||
|
}
|
||||||
|
switch code {
|
||||||
|
case .readerTransceiveErrorTagConnectionLost:
|
||||||
|
return "Tag zu früh entfernt."
|
||||||
|
case .readerTransceiveErrorRetryExceeded:
|
||||||
|
return "Keine Antwort vom Tag."
|
||||||
|
case .readerTransceiveErrorTagResponseError:
|
||||||
|
return "Tag antwortet fehlerhaft."
|
||||||
|
case .readerTransceiveErrorTagNotConnected:
|
||||||
|
return "Kein Tag verbunden."
|
||||||
|
case .readerSessionInvalidationErrorSessionTimeout:
|
||||||
|
return "Zeit abgelaufen."
|
||||||
|
case .readerSessionInvalidationErrorSystemIsBusy:
|
||||||
|
return "NFC gerade belegt."
|
||||||
|
case .readerSessionInvalidationErrorSessionTerminatedUnexpectedly:
|
||||||
|
return "Sitzung abgebrochen."
|
||||||
|
case .ndefReaderSessionErrorTagUpdateFailure:
|
||||||
|
return "Schreiben fehlgeschlagen."
|
||||||
|
case .ndefReaderSessionErrorTagNotWritable:
|
||||||
|
return "Tag nicht beschreibbar."
|
||||||
|
case .readerErrorRadioDisabled:
|
||||||
|
return "NFC ist aus."
|
||||||
|
case .readerErrorSecurityViolation:
|
||||||
|
return "NFC nicht erlaubt."
|
||||||
|
case .readerErrorUnsupportedFeature:
|
||||||
|
return "Tag-Typ nicht unterstützt."
|
||||||
|
default:
|
||||||
|
return "Fehlgeschlagen (Code \(code.rawValue))."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum Auftrag {
|
private enum Auftrag {
|
||||||
case lesen
|
case lesen
|
||||||
case schreiben(nutzlast: String, sperren: Bool)
|
case schreiben(nutzlast: String, sperren: Bool)
|
||||||
@@ -155,8 +197,10 @@ final class NFCDienst: NSObject {
|
|||||||
if let meldung {
|
if let meldung {
|
||||||
session?.alertMessage = meldung
|
session?.alertMessage = meldung
|
||||||
session?.invalidate()
|
session?.invalidate()
|
||||||
} else if case .failure = ergebnis {
|
} else if case let .failure(fehler) = ergebnis {
|
||||||
session?.invalidate()
|
// Mit Text: Ohne ihn schliesst sich Apples Blatt wortlos und die
|
||||||
|
// Meldung steht erst danach in der App.
|
||||||
|
session?.invalidate(errorMessage: fehler.localizedDescription)
|
||||||
}
|
}
|
||||||
session = nil
|
session = nil
|
||||||
fortsetzung.resume(with: ergebnis)
|
fortsetzung.resume(with: ergebnis)
|
||||||
@@ -166,7 +210,7 @@ final class NFCDienst: NSObject {
|
|||||||
private func lesen(_ tag: NFCNDEFTag) {
|
private func lesen(_ tag: NFCNDEFTag) {
|
||||||
tag.readNDEF { nachricht, fehler in
|
tag.readNDEF { nachricht, fehler in
|
||||||
if let fehler {
|
if let fehler {
|
||||||
self.fertig(.failure(Fehler.system(fehler.localizedDescription)))
|
self.fertig(.failure(Fehler.system(Self.kurz(fehler))))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let text = nachricht?.records.compactMap(Self.text(aus:)).first, !text.isEmpty else {
|
guard let text = nachricht?.records.compactMap(Self.text(aus:)).first, !text.isEmpty else {
|
||||||
@@ -187,7 +231,7 @@ final class NFCDienst: NSObject {
|
|||||||
|
|
||||||
tag.queryNDEFStatus { status, kapazitaet, fehler in
|
tag.queryNDEFStatus { status, kapazitaet, fehler in
|
||||||
if let fehler {
|
if let fehler {
|
||||||
self.fertig(.failure(Fehler.system(fehler.localizedDescription)))
|
self.fertig(.failure(Fehler.system(Self.kurz(fehler))))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch status {
|
switch status {
|
||||||
@@ -210,7 +254,7 @@ final class NFCDienst: NSObject {
|
|||||||
|
|
||||||
tag.writeNDEF(nachricht) { fehler in
|
tag.writeNDEF(nachricht) { fehler in
|
||||||
if let fehler {
|
if let fehler {
|
||||||
self.fertig(.failure(Fehler.system(fehler.localizedDescription)))
|
self.fertig(.failure(Fehler.system(Self.kurz(fehler))))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard sperren else {
|
guard sperren else {
|
||||||
@@ -224,8 +268,8 @@ final class NFCDienst: NSObject {
|
|||||||
// Das gehört gesagt, statt den ganzen Vorgang als
|
// Das gehört gesagt, statt den ganzen Vorgang als
|
||||||
// gescheitert auszugeben.
|
// gescheitert auszugeben.
|
||||||
self.fertig(.failure(Fehler.system(
|
self.fertig(.failure(Fehler.system(
|
||||||
"Tag beschrieben, aber das Sperren ist fehlgeschlagen: "
|
"Tag beschrieben, Sperren fehlgeschlagen: "
|
||||||
+ fehler.localizedDescription)))
|
+ Self.kurz(fehler))))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
AudioServicesPlaySystemSound(1057)
|
AudioServicesPlaySystemSound(1057)
|
||||||
@@ -274,7 +318,7 @@ extension NFCDienst: NFCTagReaderSessionDelegate {
|
|||||||
}
|
}
|
||||||
session.connect(to: ersteser) { fehler in
|
session.connect(to: ersteser) { fehler in
|
||||||
if let fehler {
|
if let fehler {
|
||||||
self.fertig(.failure(Fehler.system(fehler.localizedDescription)))
|
self.fertig(.failure(Fehler.system(Self.kurz(fehler))))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch self.auftrag {
|
switch self.auftrag {
|
||||||
@@ -293,6 +337,6 @@ extension NFCDienst: NFCTagReaderSessionDelegate {
|
|||||||
let abbruch = (error as? NFCReaderError)?.code
|
let abbruch = (error as? NFCReaderError)?.code
|
||||||
== .readerSessionInvalidationErrorUserCanceled
|
== .readerSessionInvalidationErrorUserCanceled
|
||||||
self.session = nil
|
self.session = nil
|
||||||
fertig(.failure(abbruch ? Fehler.abgebrochen : Fehler.system(error.localizedDescription)))
|
fertig(.failure(abbruch ? Fehler.abgebrochen : Fehler.system(Self.kurz(error))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-16
@@ -33,30 +33,40 @@ struct NFCSchreibenView: View {
|
|||||||
Text("Auf das Tag wird geschrieben: \(nutzlast)")
|
Text("Auf das Tag wird geschrieben: \(nutzlast)")
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
// Nach dem Erfolg hat das Tag seinen Inhalt. Knopf und Schalter
|
||||||
Toggle("Tag dauerhaft schreibschützen", isOn: $sperren)
|
// stehenzulassen hiesse, es noch einmal beschreiben zu wollen.
|
||||||
} footer: {
|
if !erfolg {
|
||||||
if sperren {
|
Section {
|
||||||
Text("Das lässt sich nicht rückgängig machen. Das Tag gehört danach "
|
Toggle("Tag dauerhaft schreibschützen", isOn: $sperren)
|
||||||
+ "für immer zu diesem Einzelstück und kann nicht neu beschrieben werden.")
|
} footer: {
|
||||||
.foregroundStyle(.orange)
|
if sperren {
|
||||||
} else {
|
Text("Das lässt sich nicht rückgängig machen. Das Tag gehört danach "
|
||||||
Text("Ohne Schreibschutz kannst du das Tag später einem anderen "
|
+ "für immer zu diesem Einzelstück und kann nicht neu beschrieben werden.")
|
||||||
+ "Einzelstück zuweisen.")
|
.foregroundStyle(.orange)
|
||||||
|
} else {
|
||||||
|
Text("Ohne Schreibschutz kannst du das Tag später einem anderen "
|
||||||
|
+ "Einzelstück zuweisen.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Button(laeuft ? "Tag anhalten…" : "Tag beschreiben") {
|
Button(laeuft ? "Tag anhalten…" : "Tag beschreiben") {
|
||||||
Task { await schreiben() }
|
Task { await schreiben() }
|
||||||
|
}
|
||||||
|
.disabled(laeuft)
|
||||||
}
|
}
|
||||||
.disabled(laeuft)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if erfolg {
|
if erfolg {
|
||||||
Section {
|
Section {
|
||||||
Label("Tag beschrieben.", systemImage: "checkmark.circle")
|
Label(sperren ? "Tag beschrieben und gesperrt." : "Tag beschrieben.",
|
||||||
|
systemImage: "checkmark.circle")
|
||||||
.foregroundStyle(.green)
|
.foregroundStyle(.green)
|
||||||
|
// Hier ist nichts mehr zu tun; „Fertig" gehoert deshalb in
|
||||||
|
// den Inhalt und nicht nur oben in die Leiste. Ohne das
|
||||||
|
// stuende man im Anlege-Ablauf vor einem fast leeren Blatt.
|
||||||
|
Button("Fertig") { if let onFertig { onFertig() } else { dismiss() } }
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let fehler {
|
if let fehler {
|
||||||
|
|||||||
Reference in New Issue
Block a user