Encoder et décoder une chaîne
String.utf8 donne les octets UTF-8, et Data les encode :
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
}
Le chemin du décodage comporte deux optionnels. Data(base64Encoded:) vaut nil pour un Base64 invalide, et String(data:encoding:) vaut nil quand les octets ne sont pas de l’UTF-8 valide (par exemple [0xFF, 0xFE]). Si vous préférez des caractères de remplacement à nil, utilisez String(decoding: data, as: UTF8.self).
Base64 URL-safe
Foundation ne connaît pas l’alphabet URL-safe : convertissez vous-même les caractères.
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)) // <<???>>
L’étape du remplissage est obligatoire : Data(base64Encoded: "aGk") renvoie nil. Les JWT, les jetons d’identité de Sign in with Apple et de nombreux payloads de notifications push utilisent cette forme sans remplissage. Voir Base64 ou Base64URL et le remplissage expliqué pour les détails, ou inspectez un jeton dans le décodeur JWT.
Validation : quand le décodage renvoie nil
Toute entrée invalide donne le même résultat, nil, sans message d’erreur. Toutes celles-ci ont renvoyé nil :
| Entrée | Problème |
|---|---|
PDw_Pz8-Pg== | caractères URL-safe |
aGk | remplissage manquant |
aGk=!! | déchets après le remplissage |
aGk== | trop de remplissage |
a | longueur impossible |
"aGVs\nbG8K" | saut de ligne |
" aGk=" | espace au début |
Un cas passe : aGl= (bits de remplissage non nuls) se décode en hi. Un test de validité se résume donc à Data(base64Encoded: s) != nil. Quand vous devez savoir pourquoi une chaîne échoue, le validateur Base64 indique la position et la raison, et le guide des erreurs explique chaque cas.
Pour une entrée qui contient des sauts de ligne ou des caractères parasites, l’option .ignoreUnknownCharacters ignore tout ce qui est hors de l’alphabet :
Data(base64Encoded: "aGVs\nbG8K", options: .ignoreUnknownCharacters)
// 6 bytes: "hello\n"
Réservez-la aux corps MIME ou PEM dont vous êtes sûr. Sur une entrée quelconque, elle masque les erreurs, car les caractères URL-safe sont ignorés eux aussi et le résultat est faux sans que rien ne le signale.
Options de découpage des lignes
base64EncodedString(options:) peut couper les lignes à 64 ou 76 caractères. La fin de ligne par défaut est 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)
Pour des fins de ligne Unix, combinez l’option de longueur avec .endLineWithLineFeed seulement : [.lineLength76Characters, .endLineWithLineFeed]. Sans aucune option, la sortie tient sur une seule ligne, ce qu’il vous faut pour le JSON, les URL et les en-têtes. Pour l’e-mail, l’encodeur Base64 MIME montre la mise en forme à 76 caractères.
Encoder et décoder un fichier
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"))
Le déballage forcé passe dans un playground ; dans une app, utilisez guard let sur le Data décodé et signalez une erreur.
Gros fichiers par blocs
Foundation n’a pas d’encodeur Base64 en flux. Lisez le fichier par blocs dont la taille est un multiple de 3, pour qu’aucun remplissage ne tombe au milieu :
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))
}
}
Encoder ainsi un fichier de test de 300 Ko a donné la même chaîne qu’un encodage en un seul appel. read(upToCount:) et write(contentsOf:) demandent macOS 10.15.4 / iOS 13.4 ou plus récent. Le guide du surcoût de taille explique pourquoi la sortie fait environ 4/3 de l’entrée.
Pièges
- Attendre un message d’erreur.
Data(base64Encoded:)se contente de dire « non ». Pour déboguer, journalisez la longueur de l’entrée et ses premiers caractères. - Les préfixes de data URI. Les chaînes issues de web views commencent souvent par
data:image/png;base64,. Coupez à la première virgule avant de décoder, sinon le résultat estnil. String(describing: data). Afficher unDatamontre quelque chose comme6 bytes, pas son contenu. Utilisezbase64EncodedString()ouString(decoding:as:).- Considérer Base64 comme un stockage sécurisé. Utilisez le trousseau (Keychain) pour les secrets ; Base64 est lisible par n’importe qui. Voir encodage ou chiffrement.
FAQ
Pourquoi Data(base64Encoded:) renvoie-t-il nil ?
L’initialiseur renvoie nil pour toute entrée invalide au lieu de lever une erreur : remplissage manquant, - ou _ URL-safe, espaces, sauts de ligne ou préfixe data:. Corrigez d’abord l’entrée, ou passez options: .ignoreUnknownCharacters pour une entrée découpée en lignes.
Swift gère-t-il Base64URL nativement ?
Foundation n’a pas d’option URL-safe. Après l’encodage, remplacez + par - et / par _ et supprimez = ; avant le décodage, faites l’inverse et rétablissez le remplissage.
Comment convertir une UIImage en Base64 en Swift ?
Obtenez d’abord les octets, par exemple avec image.pngData() ou image.jpegData(compressionQuality: 0.8), puis appelez .base64EncodedString() sur le résultat. Pour vérifier la sortie, collez-la dans Base64 en image.