I've removed jsonCallback (
and )
from the URL https://www.apple.com/support/systemstatus/data/developer/system_status_en_US.js using the below.
var dataString = String(data: data, encoding: .utf8)
dataString = dataString?.replacingOccurrences(of: "jsonCallback(", with: "")
dataString = dataString?.replacingOccurrences(of: ");", with: "")
let json = dataString?.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json)
The error I'm getting back
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))
I can't find where the mismatch is happening at because when I look at dataString
and piece it back together the JSON decoding model appears to match.
Here's the full code:
func fetchSystemStatus() async -> [SystemStatus] {
guard let url = URL(string: systemStatusURL) else {
return []
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
// This is commented out data to try and gather developer system status
var dataString = String(data: data, encoding: .utf8)
dataString = dataString?.replacingOccurrences(of: "jsonCallback(", with: "")
dataString = dataString?.replacingOccurrences(of: ");", with: "")
let json = dataString?.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json)
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
print("\(#function) \(response)")
return []
}
let statusData = try JSONDecoder().decode(SystemStatus.self, from: jsonData)
return [statusData]
} catch {
print("\(#function) \(error)")
return []
}
}
Model:
// MARK: - SystemStatus
struct SystemStatus: Codable {
let services: [Service]
enum CodingKeys: String, CodingKey {
case services = "services"
}
}
// MARK: - Service
struct Service: Codable, Identifiable {
let id = UUID()
let redirectURL: String?
let events: [Event]
let serviceName: String
enum CodingKeys: String, CodingKey {
case redirectURL = "redirectUrl"
case events = "events"
case serviceName = "serviceName"
}
}
// MARK: - Event
struct Event: Codable {
let usersAffected: String
let epochStartDate: Int
let epochEndDate: Int
let messageID: String
let statusType: String
let datePosted: String
let startDate: String
let endDate: String
let affectedServices: [String]?
let eventStatus: String
let message: String
enum CodingKeys: String, CodingKey {
case usersAffected = "usersAffected"
case epochStartDate = "epochStartDate"
case epochEndDate = "epochEndDate"
case messageID = "messageId"
case statusType = "statusType"
case datePosted = "datePosted"
case startDate = "startDate"
case endDate = "endDate"
case affectedServices = "affectedServices"
case eventStatus = "eventStatus"
case message = "message"
}
}
CodePudding user response:
This should work:
let statusData = try JSONDecoder().decode(SystemStatus.self, from: Data(json!))
or
let statusData = try JSONDecoder().decode(SystemStatus.self, from: Data(dataString!.utf8))
What's your issue:
let jsonData = try JSONEncoder().encode(json)
But json
here is Data
, so if you call JSONEncoder
on it, by default, it will use Base64, so it won't be like the JSON you expect.
But json
already is correct.
CodePudding user response:
The problem is that you encode data of the string not the model here
let json = dataString!.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json) // < here is the problem
so you get an invalid data that doesn't represent your json string , BTW you don't need to use JSONEncoder()
to convert the json string to data you need to supply that data directly to JSONDecoder()
let statusData = try JSONDecoder().decode(SystemStatus.self, from: json!)
to get it to work