Datei hochladen
  1. base64hub
  2. Base64 im Code
  3. Swift
Code

Base64 in Swift

Swift verwendet für Base64 den Typ Data aus Foundation: eine Methode zum Kodieren, ein failable Initializer zum Dekodieren. Die Snippets unten liefen mit Swift 6.1 unter Linux, das dieselbe Foundation-API wie die Apple-Plattformen nutzt.

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:

EingabeProblem
PDw_Pz8-Pg==URL-sichere Zeichen
aGkfehlendes Padding
aGk=!!Datenmüll nach dem Padding
aGk==zu viel Padding
aunmö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 Ergebnis nil.
  • String(describing: data). Die Ausgabe von Data zeigt etwas wie 6 bytes, nicht den Inhalt. Verwenden Sie base64EncodedString() oder String(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.

Weiterlesen