Base64 Strings for Data initialization

I am trying to initialize a base64 string and its causing errors each time I try to code it. Even without "=", "/" or "+", I still get issues.

let string = "DASD=M3R43=MKL4=LN34=KNKNK43=DWSDWD1=RWR24=FSF2=DS22=FSF1231=FSAFA21=D653=4404=9DE1=1033C1611DB8"
let data1 = try! JSONEncoder().encode(string)
// error 1
guard let data2 = try? JSONEncoder().encode(string) else {
    // error 2
    return
}

let data3 = Data.init(base64Encoded: string)!
// error 3 : late night . "string" is not base64 because "=" is not part of base 54.

#1 and #2 are because JSON does not allow top level strings, it has to be an object or an array, IIRC.
Error #3 is due to the fact that your string is not a valid base64 sequence.

The JSON spec seems to allow any of its values to be at the top-level (following the grammar on the right of that page: string -> "ws value ws" (with empty whitespace) -> element -> json). However, it is an explicit decision of JSONEncoder to enforce that some things don't appear there, so maybe @itaiferber could provide more insight.

Edit: ah, [SR-8038] JSONEncoder for bool, number and string value fails · Issue #3674 · apple/swift-corelibs-foundation · GitHub provides some answers.

2 Likes

I see . Thank you. I do still have an issue. Lets say below, the Foo structure has an Data? variable. When you set the Data? variable with a custom object to the Foo structure from Bar, if you initialize a utf8 JSON Encoded string, it doesn't show the Data? variable printed.

var foo = Foo(name: "XFXFXF")
    
let bar = Bar(name: "XFXFARASR")
    
guard let barData = try? JSONEncoder().encode(bar) else {
    return
}
    
foo.data = bar.name
guard let fooData = try? JSONEncoder().encode(foo) else {
    return
}
// doesn't print foo.data which is a bar object
let stringFoo = String.init(data: fooData, encoding: .utf8)
// prints the whole bar object
let stringBar = String.init(data: barData, encoding: .utf8)

You are right about #3.. It was late night. But it still giving errors when you take out the "=". Is the encoding scheme suppose to be .utf8 ?

Regarding fragments, see also Top-level \(T.self) encoded as number JSON fragment, Allowing top-level fragments in JSONDecoder, and SR-6163.

As for the other issues you're hitting:

  • It's impossible to tell why foo.data isn't printed without seeing the full definitions of Foo and Bar — can you share those? (As well as the actual contents of stringFoo and stringBar)
  • What is the full string you're passing to init(base64Encoded:) now? We should be able to tell if it's a valid base-64 encoded string or not

Its okay. I got the hang of it. The SRs posted above help me understand it better.