Strings fetched with JSON-API to be converted from base64 to UTF8 in Swift
up vote
0
down vote
favorite
I am developing an iOS App that fetches Trivia Questions from Open Trivia Database (API)
After reading the docs and played around with it I think that the best solution is to use base64 encoding (since it seems to be supported in Swift). I have successfully fetched the data and parsed it into structs using a JSONParser. The problem that I have to solve is how to convert the values from base64 to UTF8. (The keys are read correctly, and therefore it maps to my structs)
My first idea was to use decoder.dataDecodingStrategy = .base64
, but that does not seem to have any effect at all. And I am not really sure why.
Is that the right way to do it, or should I decode it myself afterwards when the strings are read in to structs?
In short, the result of the Parsing is a struct containing a responseCode as an Int and array containing structs representing the questions with the strings that I want to convert to UTF8 as members
My code for parsing looks like this:
let urlPath = "https://opentdb.com/api.php?amount=10&encode=base64"
let apiURL = URL(string: urlPath)!
URLSession.shared.dataTask(with: apiURL) (data, response, error) in
guard let data = data else return
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch let err
print("Error", err)
.resume()
json swift utf-8 character-encoding base64
add a comment |
up vote
0
down vote
favorite
I am developing an iOS App that fetches Trivia Questions from Open Trivia Database (API)
After reading the docs and played around with it I think that the best solution is to use base64 encoding (since it seems to be supported in Swift). I have successfully fetched the data and parsed it into structs using a JSONParser. The problem that I have to solve is how to convert the values from base64 to UTF8. (The keys are read correctly, and therefore it maps to my structs)
My first idea was to use decoder.dataDecodingStrategy = .base64
, but that does not seem to have any effect at all. And I am not really sure why.
Is that the right way to do it, or should I decode it myself afterwards when the strings are read in to structs?
In short, the result of the Parsing is a struct containing a responseCode as an Int and array containing structs representing the questions with the strings that I want to convert to UTF8 as members
My code for parsing looks like this:
let urlPath = "https://opentdb.com/api.php?amount=10&encode=base64"
let apiURL = URL(string: urlPath)!
URLSession.shared.dataTask(with: apiURL) (data, response, error) in
guard let data = data else return
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch let err
print("Error", err)
.resume()
json swift utf-8 character-encoding base64
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I am developing an iOS App that fetches Trivia Questions from Open Trivia Database (API)
After reading the docs and played around with it I think that the best solution is to use base64 encoding (since it seems to be supported in Swift). I have successfully fetched the data and parsed it into structs using a JSONParser. The problem that I have to solve is how to convert the values from base64 to UTF8. (The keys are read correctly, and therefore it maps to my structs)
My first idea was to use decoder.dataDecodingStrategy = .base64
, but that does not seem to have any effect at all. And I am not really sure why.
Is that the right way to do it, or should I decode it myself afterwards when the strings are read in to structs?
In short, the result of the Parsing is a struct containing a responseCode as an Int and array containing structs representing the questions with the strings that I want to convert to UTF8 as members
My code for parsing looks like this:
let urlPath = "https://opentdb.com/api.php?amount=10&encode=base64"
let apiURL = URL(string: urlPath)!
URLSession.shared.dataTask(with: apiURL) (data, response, error) in
guard let data = data else return
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch let err
print("Error", err)
.resume()
json swift utf-8 character-encoding base64
I am developing an iOS App that fetches Trivia Questions from Open Trivia Database (API)
After reading the docs and played around with it I think that the best solution is to use base64 encoding (since it seems to be supported in Swift). I have successfully fetched the data and parsed it into structs using a JSONParser. The problem that I have to solve is how to convert the values from base64 to UTF8. (The keys are read correctly, and therefore it maps to my structs)
My first idea was to use decoder.dataDecodingStrategy = .base64
, but that does not seem to have any effect at all. And I am not really sure why.
Is that the right way to do it, or should I decode it myself afterwards when the strings are read in to structs?
In short, the result of the Parsing is a struct containing a responseCode as an Int and array containing structs representing the questions with the strings that I want to convert to UTF8 as members
My code for parsing looks like this:
let urlPath = "https://opentdb.com/api.php?amount=10&encode=base64"
let apiURL = URL(string: urlPath)!
URLSession.shared.dataTask(with: apiURL) (data, response, error) in
guard let data = data else return
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch let err
print("Error", err)
.resume()
json swift utf-8 character-encoding base64
json swift utf-8 character-encoding base64
asked Nov 10 at 21:06
Måns Sandberg
4718
4718
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
Base64 encoding is used for properties you declared as Data, not as Strings, like so:
struct Response: Codable
let someBaseEncodedString: Data
var someString: String?
get
return String(data: someBaseEncodedString, encoding: .utf8)
So, for the example you are giving, all the properties that are returned as a base64 encoded string should have the Data type in your struct, and then after that decoded as strings.
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
add a comment |
up vote
0
down vote
As suggested by other answers, you can decode Data
or Base-64 String
after JSONSerialization
or JSONDecoder
decoded the API results.
But if you prefer to write decoding initializer, you can make it as follows:
This may not be much different from your own Response
, I guess.
struct Response: Codable
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey
case responseCode = "response_code"
case results
To prepare to write a decoding initializer for Response
, I would like to use some extensions:
extension KeyedDecodingContainer
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
return string
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String]
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] =
while !arrContainer.isAtEnd
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
strings.append(string)
return strings
Using these extensions above, you can define the Result
type as follows:
extension Response
struct Result: Codable
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
(You have not mentioned if your Response
(or other name?) is defined as a nested type or not, but I think you can rename or modify it yourself.)
With all things above, you can simply decode the API response as:
do
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch
print("Error", error)
By the way, you say I think that the best solution is to use base64 encoding (since it seems to be supported in Swift), but is that really true?
Base-64 to Data
is supported in JSONDecoder
, but it is not what you expect. So, using another encoding can be a better choice.
But, anyway, JSON string can represent all unicode characters using only ASCII with uXXXX
or uHHHHuLLLL
. So, I do not understand why the API designers do not provide an option Standard JSON Encoding. If you can contact to them, please tell them to provide the option, that may simplify many client side codes.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Base64 encoding is used for properties you declared as Data, not as Strings, like so:
struct Response: Codable
let someBaseEncodedString: Data
var someString: String?
get
return String(data: someBaseEncodedString, encoding: .utf8)
So, for the example you are giving, all the properties that are returned as a base64 encoded string should have the Data type in your struct, and then after that decoded as strings.
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
add a comment |
up vote
1
down vote
accepted
Base64 encoding is used for properties you declared as Data, not as Strings, like so:
struct Response: Codable
let someBaseEncodedString: Data
var someString: String?
get
return String(data: someBaseEncodedString, encoding: .utf8)
So, for the example you are giving, all the properties that are returned as a base64 encoded string should have the Data type in your struct, and then after that decoded as strings.
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Base64 encoding is used for properties you declared as Data, not as Strings, like so:
struct Response: Codable
let someBaseEncodedString: Data
var someString: String?
get
return String(data: someBaseEncodedString, encoding: .utf8)
So, for the example you are giving, all the properties that are returned as a base64 encoded string should have the Data type in your struct, and then after that decoded as strings.
Base64 encoding is used for properties you declared as Data, not as Strings, like so:
struct Response: Codable
let someBaseEncodedString: Data
var someString: String?
get
return String(data: someBaseEncodedString, encoding: .utf8)
So, for the example you are giving, all the properties that are returned as a base64 encoded string should have the Data type in your struct, and then after that decoded as strings.
edited Nov 10 at 21:36
answered Nov 10 at 21:28
Marcel
4,11011833
4,11011833
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
add a comment |
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
This helped me out very much and I did not have to change a lot of my code. Thanks!
– Måns Sandberg
Nov 13 at 16:16
add a comment |
up vote
0
down vote
As suggested by other answers, you can decode Data
or Base-64 String
after JSONSerialization
or JSONDecoder
decoded the API results.
But if you prefer to write decoding initializer, you can make it as follows:
This may not be much different from your own Response
, I guess.
struct Response: Codable
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey
case responseCode = "response_code"
case results
To prepare to write a decoding initializer for Response
, I would like to use some extensions:
extension KeyedDecodingContainer
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
return string
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String]
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] =
while !arrContainer.isAtEnd
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
strings.append(string)
return strings
Using these extensions above, you can define the Result
type as follows:
extension Response
struct Result: Codable
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
(You have not mentioned if your Response
(or other name?) is defined as a nested type or not, but I think you can rename or modify it yourself.)
With all things above, you can simply decode the API response as:
do
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch
print("Error", error)
By the way, you say I think that the best solution is to use base64 encoding (since it seems to be supported in Swift), but is that really true?
Base-64 to Data
is supported in JSONDecoder
, but it is not what you expect. So, using another encoding can be a better choice.
But, anyway, JSON string can represent all unicode characters using only ASCII with uXXXX
or uHHHHuLLLL
. So, I do not understand why the API designers do not provide an option Standard JSON Encoding. If you can contact to them, please tell them to provide the option, that may simplify many client side codes.
add a comment |
up vote
0
down vote
As suggested by other answers, you can decode Data
or Base-64 String
after JSONSerialization
or JSONDecoder
decoded the API results.
But if you prefer to write decoding initializer, you can make it as follows:
This may not be much different from your own Response
, I guess.
struct Response: Codable
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey
case responseCode = "response_code"
case results
To prepare to write a decoding initializer for Response
, I would like to use some extensions:
extension KeyedDecodingContainer
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
return string
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String]
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] =
while !arrContainer.isAtEnd
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
strings.append(string)
return strings
Using these extensions above, you can define the Result
type as follows:
extension Response
struct Result: Codable
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
(You have not mentioned if your Response
(or other name?) is defined as a nested type or not, but I think you can rename or modify it yourself.)
With all things above, you can simply decode the API response as:
do
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch
print("Error", error)
By the way, you say I think that the best solution is to use base64 encoding (since it seems to be supported in Swift), but is that really true?
Base-64 to Data
is supported in JSONDecoder
, but it is not what you expect. So, using another encoding can be a better choice.
But, anyway, JSON string can represent all unicode characters using only ASCII with uXXXX
or uHHHHuLLLL
. So, I do not understand why the API designers do not provide an option Standard JSON Encoding. If you can contact to them, please tell them to provide the option, that may simplify many client side codes.
add a comment |
up vote
0
down vote
up vote
0
down vote
As suggested by other answers, you can decode Data
or Base-64 String
after JSONSerialization
or JSONDecoder
decoded the API results.
But if you prefer to write decoding initializer, you can make it as follows:
This may not be much different from your own Response
, I guess.
struct Response: Codable
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey
case responseCode = "response_code"
case results
To prepare to write a decoding initializer for Response
, I would like to use some extensions:
extension KeyedDecodingContainer
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
return string
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String]
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] =
while !arrContainer.isAtEnd
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
strings.append(string)
return strings
Using these extensions above, you can define the Result
type as follows:
extension Response
struct Result: Codable
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
(You have not mentioned if your Response
(or other name?) is defined as a nested type or not, but I think you can rename or modify it yourself.)
With all things above, you can simply decode the API response as:
do
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch
print("Error", error)
By the way, you say I think that the best solution is to use base64 encoding (since it seems to be supported in Swift), but is that really true?
Base-64 to Data
is supported in JSONDecoder
, but it is not what you expect. So, using another encoding can be a better choice.
But, anyway, JSON string can represent all unicode characters using only ASCII with uXXXX
or uHHHHuLLLL
. So, I do not understand why the API designers do not provide an option Standard JSON Encoding. If you can contact to them, please tell them to provide the option, that may simplify many client side codes.
As suggested by other answers, you can decode Data
or Base-64 String
after JSONSerialization
or JSONDecoder
decoded the API results.
But if you prefer to write decoding initializer, you can make it as follows:
This may not be much different from your own Response
, I guess.
struct Response: Codable
var responseCode: Int
var results: [Result]
enum CodingKeys: String, CodingKey
case responseCode = "response_code"
case results
To prepare to write a decoding initializer for Response
, I would like to use some extensions:
extension KeyedDecodingContainer
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> String
guard let string = try self.decode(String.self, forKey: key).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
return string
func decodeBase64(forKey key: Key, encoding: String.Encoding) throws -> [String]
var arrContainer = try self.nestedUnkeyedContainer(forKey: key)
var strings: [String] =
while !arrContainer.isAtEnd
guard let string = try arrContainer.decode(String.self).decodeBase64(encoding: encoding) else
throw DecodingError.dataCorruptedError(forKey: key, in: self,
debugDescription: "Not a valid Base-64 representing UTF-8")
strings.append(string)
return strings
Using these extensions above, you can define the Result
type as follows:
extension Response
struct Result: Codable
var category: String
var type: String
var difficulty: String
var question: String
var correctAnswer: String
var incorrectAnswers: [String]
enum CodingKeys: String, CodingKey
case category
case type
case difficulty
case question
case correctAnswer = "correct_answer"
case incorrectAnswers = "incorrect_answers"
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.category = try container.decodeBase64(forKey: .category, encoding: .utf8)
self.type = try container.decodeBase64(forKey: .type, encoding: .utf8)
self.difficulty = try container.decodeBase64(forKey: .difficulty, encoding: .utf8)
self.question = try container.decodeBase64(forKey: .question, encoding: .utf8)
self.correctAnswer = try container.decodeBase64(forKey: .correctAnswer, encoding: .utf8)
self.incorrectAnswers = try container.decodeBase64(forKey: .incorrectAnswers, encoding: .utf8)
(You have not mentioned if your Response
(or other name?) is defined as a nested type or not, but I think you can rename or modify it yourself.)
With all things above, you can simply decode the API response as:
do
let decoder = JSONDecoder()
let questionData = try decoder.decode(Response.self, from: data)
print(questionData)
catch
print("Error", error)
By the way, you say I think that the best solution is to use base64 encoding (since it seems to be supported in Swift), but is that really true?
Base-64 to Data
is supported in JSONDecoder
, but it is not what you expect. So, using another encoding can be a better choice.
But, anyway, JSON string can represent all unicode characters using only ASCII with uXXXX
or uHHHHuLLLL
. So, I do not understand why the API designers do not provide an option Standard JSON Encoding. If you can contact to them, please tell them to provide the option, that may simplify many client side codes.
answered Nov 11 at 2:05
OOPer
33.4k46083
33.4k46083
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53243404%2fstrings-fetched-with-json-api-to-be-converted-from-base64-to-utf8-in-swift%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown