Einen String kodieren und dekodieren
String.utf8 liefert die UTF-8-Bytes, Data kodiert sie:
import Foundation
let enc = Data("héllo wörld".utf8).base64EncodedString()
print(enc) // aMOpbGxvIHfDtnJsZA==
if let data = Data(base64Encoded: enc),
let s = String(data: data, encoding: .utf8) {
print(s) // héllo wörld
}
Auf dem Weg zum dekodierten Text liegen zwei Optionals. Data(base64Encoded:) ist nil bei ungültigem Base64, und String(data:encoding:) ist nil, wenn die Bytes kein gültiges UTF-8 sind (zum Beispiel [0xFF, 0xFE]). Sind Ihnen Ersatzzeichen lieber als nil, verwenden Sie String(decoding: data, as: UTF8.self).
URL-sicheres Base64
Foundation kennt das URL-sichere Alphabet nicht, wandeln Sie die Zeichen also selbst um:
let d = Data("<<???>>".utf8)
let b64url = d.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
print(b64url) // PDw_Pz8-Pg
func base64URLDecode(_ s: String) -> Data? {
var b = s.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
b += String(repeating: "=", count: (4 - b.count % 4) % 4)
return Data(base64Encoded: b)
}
print(String(decoding: base64URLDecode("PDw_Pz8-Pg")!, as: UTF8.self)) // <<???>>
Der Padding-Schritt ist Pflicht: Data(base64Encoded: "aGk") liefert nil. JWTs, Identity-Tokens von „Mit Apple anmelden“ und viele Payloads von Push-Benachrichtigungen verwenden diese Form ohne Padding. Details unter Base64 vs. Base64URL und Padding erklärt, oder sehen Sie sich ein Token im JWT-Decoder an.
Validierung: wenn das Dekodieren nil liefert
Jede ungültige Eingabe führt zum selben Ergebnis, nil, ohne Fehlermeldung. All diese Eingaben lieferten nil:
| Eingabe | Problem |
|---|---|
PDw_Pz8-Pg== | URL-sichere Zeichen |
aGk | fehlendes Padding |
aGk=!! | Datenmüll nach dem Padding |
aGk== | zu viel Padding |
a | unmögliche Länge |
"aGVs\nbG8K" | Zeilenumbruch |
" aGk=" | führendes Leerzeichen |
Ein Fall kommt durch: aGl= (Padding-Bits ungleich null) wird zu hi dekodiert. Eine Gültigkeitsprüfung ist also schlicht Data(base64Encoded: s) != nil. Wenn Sie wissen müssen, warum ein String scheitert, meldet der Base64-Validator Position und Grund, und die Anleitung zu Base64-Fehlern erklärt jeden einzelnen.
Für Eingaben mit Zeilenumbrüchen oder verirrten Zeichen überspringt die Option .ignoreUnknownCharacters alles außerhalb des Alphabets:
Data(base64Encoded: "aGVs\nbG8K", options: .ignoreUnknownCharacters)
// 6 bytes: "hello\n"
Verwenden Sie sie für MIME- oder PEM-Inhalte, denen Sie vertrauen. Bei beliebigen Eingaben verdeckt sie Fehler, denn auch URL-sichere Zeichen werden übersprungen, und das Ergebnis ist stillschweigend falsch.
Optionen für den Zeilenumbruch
base64EncodedString(options:) kann Zeilen nach 64 oder 76 Zeichen umbrechen. Das Zeilenende ist standardmäßig CRLF:
let x = Data(String(repeating: "x", count: 60).utf8)
x.base64EncodedString(options: .lineLength76Characters)
// "eHh4eHh4...eHh4\r\neHh4" (76 chars, CRLF, rest)
x.base64EncodedString(options: .lineLength64Characters)
// 64 chars, "\r\n", 16 chars (PEM-style)
Für Unix-Zeilenenden kombinieren Sie die Längenoption nur mit .endLineWithLineFeed: [.lineLength76Characters, .endLineWithLineFeed]. Ohne Option ist die Ausgabe eine einzige Zeile, und genau die wollen Sie für JSON, URLs und Header. Für E-Mail zeigt der MIME-Base64-Encoder das Layout mit 76 Zeichen.
Eine Datei kodieren und dekodieren
let url = URL(fileURLWithPath: "hello.txt")
let b64 = try Data(contentsOf: url).base64EncodedString()
print(b64) // aGVsbG8K
try Data(base64Encoded: "aGVsbG8K")!.write(to: URL(fileURLWithPath: "copy.txt"))
Force-Unwrapping ist in einem Playground in Ordnung; in einer App sichern Sie das dekodierte Data mit guard let ab und melden einen Fehler.
Große Dateien in Blöcken
Foundation hat keinen Streaming-Encoder für Base64. Lesen Sie die Datei in Blöcken, deren Größe ein Vielfaches von 3 ist, damit kein Padding in der Mitte landet:
func encodeFile(from src: URL, to dst: URL) throws {
_ = FileManager.default.createFile(atPath: dst.path, contents: nil)
let input = try FileHandle(forReadingFrom: src)
let output = try FileHandle(forWritingTo: dst)
defer { try? input.close(); try? output.close() }
while let chunk = try input.read(upToCount: 3 * 64 * 1024), !chunk.isEmpty {
try output.write(contentsOf: Data(chunk.base64EncodedString().utf8))
}
}
So kodiert, ergab eine 300-KB-Testdatei denselben String wie in einem einzigen Aufruf. read(upToCount:) und write(contentsOf:) brauchen macOS 10.15.4 / iOS 13.4 oder neuer. Die Anleitung zum Größenzuwachs erklärt, warum die Ausgabe etwa 4/3 der Eingabe beträgt.
Fallstricke
- Eine Fehlermeldung erwarten.
Data(base64Encoded:)sagt nur „nein“. Loggen Sie zur Fehlersuche die Eingabelänge und die ersten Zeichen. - Data-URI-Präfixe. Strings aus Web-Views beginnen oft mit
data:image/png;base64,. Schneiden Sie vor dem Dekodieren am ersten Komma ab, sonst ist das Ergebnisnil. String(describing: data). Die Ausgabe vonDatazeigt etwas wie6 bytes, nicht den Inhalt. Verwenden Siebase64EncodedString()oderString(decoding:as:).- Base64 als sicheren Speicher betrachten. Für Secrets nehmen Sie den Schlüsselbund (Keychain); Base64 kann jeder lesen. Siehe Kodierung vs. Verschlüsselung.
Häufige Fragen
Warum liefert Data(base64Encoded:) nil?
Der Initializer liefert bei jeder ungültigen Eingabe nil, statt einen Fehler zu werfen: bei fehlendem Padding, URL-sicheren - oder _, Leerzeichen, Zeilenumbrüchen oder einem data:-Präfix. Korrigieren Sie zuerst die Eingabe oder übergeben Sie bei umbrochenen Eingaben options: .ignoreUnknownCharacters.
Unterstützt Swift Base64URL von Haus aus?
Foundation hat keine URL-sichere Option. Ersetzen Sie nach dem Kodieren + durch - und / durch _ und entfernen Sie =; vor dem Dekodieren kehren Sie das um und stellen das Padding wieder her.
Wie wandle ich in Swift ein UIImage in Base64 um?
Holen Sie sich zuerst die Bytes, etwa mit image.pngData() oder image.jpegData(compressionQuality: 0.8), und rufen Sie dann .base64EncodedString() auf dem Ergebnis auf. Zur Kontrolle fügen Sie die Ausgabe in Base64 in Bild ein.