I have Codables running now. But the API has some String entries that can sometimes have an Int
value of 0
if they are empty. I was searching here and found this: Swift 4 Codable - Bool or String values But I'm not able to get it running
My struct
struct check : Codable {
let test : Int
let rating : String?
}
Rating is most of the time something like "1Star"
. But if there is no rating I get 0
as Int back.
I'm parsing the data like this:
enum Result<Value> {
case success(Value)
case failure(Error)
}
func checkStar(for userId: Int, completion: ((Result<check>) -> Void)?) {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "xyz.com"
urlComponents.path = "/api/stars"
let userIdItem = URLQueryItem(name: "userId", value: "\(userId)")
urlComponents.queryItems = [userIdItem]
guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
var request = URLRequest(url: url)
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
"Authorization": "Bearer \(keytoken)"
]
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonData = responseData {
// Now we have jsonData, Data representation of the JSON returned to us
// from our URLRequest...
// Create an instance of JSONDecoder to decode the JSON data to our
// Codable struct
let decoder = JSONDecoder()
do {
// We would use Post.self for JSON representing a single Post
// object, and [Post].self for JSON representing an array of
// Post objects
let posts = try decoder.decode(check.self, from: jsonData)
completion?(.success(posts))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
Loading it:
func loadStars() {
checkStar(for: 1) { (result) in
switch result {
case .success(let goo):
dump(goo)
case .failure(let error):
fatalError(error.localizedDescription)
}
}
}
I hope someone can help me there, cause I'm not completely sure how this parsing, etc. works.
you may implement your own decode init method, get each class property from decode container, during this section, make your logic dealing with wether "rating" is an Int or String, sign all required class properties at last.
here is a simple demo i made:
class Demo: Decodable {
var test = 0
var rating: String?
enum CodingKeys: String, CodingKey {
case test
case rating
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let test = try container.decode(Int.self, forKey: .test)
let ratingString = try? container.decode(String.self, forKey: .rating)
let ratingInt = try? container.decode(Int.self, forKey: .rating)
self.rating = ratingString ?? (ratingInt == 0 ? "rating is nil or 0" : "rating is integer but not 0")
self.test = test
}
}
let jsonDecoder = JSONDecoder()
let result = try! jsonDecoder.decode(Demo.self, from: YOUR-JSON-DATA)
you may modify decoded "rating" result, that should be easy.
hope this could give you a little help. :)
for more info: Apple's encoding and decoding doc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With