Еще один недопустимый тип верхнего уровня при сбое записи в формате JSON

#ios #swift5 #nsjsonserialization #jsonencoder

Вопрос:

Итак, Xcode 13.1, iOS 15.0, я застрял с этой сериализацией JSON для довольно важного проекта, который должен быть доставлен вчера (!), как обычно, и вместо этого вылетает.

Это тот фрагмент кода, с которым я имею дело:

 var jsonData: Data  do {  jsonData = try JSONSerialization.data(withJSONObject: roomBookings, options: [])  } catch {  print("error: ", error)  return false  }  

Это объект, который я пытаюсь сериализовать в формате JSON:

 Rooms.RoomBookings( bookings: [Rooms.RoomBooking( bookingID: "23EB86CB-A918-47D4-ADDB-346DBB4E3471",  roomID: "BgX86SbN0UifijkwU8HZ",  isAllDay: false,  startTimestamp: 1636440856861,  endTimestamp: 1636444456861,  user: "trialUser") ])  

Это ошибка, которую я продолжаю получать, что приводит к сбою приложения (конечно, мы можем избежать фактической проверки сбоя с помощью isValidJSONObject, но здесь дело не в этом).

 Terminating app due to uncaught exception 'NSInvalidArgumentException',  reason: '***  [NSJSONSerialization dataWithJSONObject:options:error:]:  Invalid top-level type in JSON write'  

Вот ниже приведена модель, ошибка сосредоточена на типе верхнего уровня, что в этом плохого? Это просто набор экземпляров Roobooking, соответствующих кодируемым, и что с того?

Кто-нибудь знает, что я делаю не так? Это было бы очень ценно!

 // MARK: - RoomBookings struct RoomBookings: Codable {  var bookings: [RoomBooking]   enum CodingKeys: String, CodingKey {  case bookings = "bookings"  } }  // MARK: RoomBookings convenience initializers and mutators extension RoomBookings {  init(data: Data) throws {  self = try newJSONDecoder().decode(RoomBookings.self, from: data)  }   init(_ json: String, using encoding: String.Encoding = .utf8) throws {  guard let data = json.data(using: encoding) else {  throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)  }  try self.init(data: data)  }   init(fromURL url: URL) throws {  try self.init(data: try Data(contentsOf: url))  }   func with(  bookings: [RoomBooking]? = nil  ) -gt; RoomBookings {  return RoomBookings(  bookings: bookings ?? self.bookings  )  }   func jsonData() throws -gt; Data {  return try newJSONEncoder().encode(self)  }   func jsonString(encoding: String.Encoding = .utf8) throws -gt; String? {  return String(data: try self.jsonData(), encoding: encoding)  } }  // MARK: - RoomBooking struct RoomBooking: Codable {  var bookingID: String  var roomID: String  var isAllDay: Bool  var startTimestamp: Int  var endTimestamp: Int  var user: String   enum CodingKeys: String, CodingKey {  case bookingID = "bookingId"  case roomID = "roomId"  case isAllDay = "isAllDay"  case startTimestamp = "startTimestamp"  case endTimestamp = "endTimestamp"  case user = "user"  } }  // MARK: RoomBooking convenience initializers and mutators  extension RoomBooking {  init(data: Data) throws {  self = try newJSONDecoder().decode(RoomBooking.self, from: data)  }   init(_ json: String, using encoding: String.Encoding = .utf8) throws {  guard let data = json.data(using: encoding) else {  throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)  }  try self.init(data: data)  }   init(fromURL url: URL) throws {  try self.init(data: try Data(contentsOf: url))  }   func with(  bookingID: String? = nil,  roomID: String? = nil,  isAllDay: Bool? = nil,  startTimestamp: Int? = nil,  endTimestamp: Int? = nil,  user: String? = nil  ) -gt; RoomBooking {  return RoomBooking(  bookingID: bookingID ?? self.bookingID,  roomID: roomID ?? self.roomID,  isAllDay: isAllDay ?? self.isAllDay,  startTimestamp: startTimestamp ?? self.startTimestamp,  endTimestamp: endTimestamp ?? self.endTimestamp,  user: user ?? self.user  )  }   func jsonData() throws -gt; Data {  return try newJSONEncoder().encode(self)  }   func jsonString(encoding: String.Encoding = .utf8) throws -gt; String? {  return String(data: try self.jsonData(), encoding: encoding)  } }  // MARK: - Helper functions for creating encoders and decoders  func newJSONDecoder() -gt; JSONDecoder {  let decoder = JSONDecoder()  if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {  decoder.dateDecodingStrategy = .iso8601  }  return decoder }  func newJSONEncoder() -gt; JSONEncoder {  let encoder = JSONEncoder()  if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {  encoder.dateEncodingStrategy = .iso8601  }  return encoder }  

Комментарии:

1. почему бы просто не использовать try JSONEncoder().encode(roomBookings)

Ответ №1:

Попробуй

 var jsonData: Data  do {  jsonData = try JSONEncoder().encode(roomBookings)  print(String(data: data, encoding: .utf8)!) //to check the actual O/P am adding it here, remove it from your code  } catch {  print("error: ", error)  return false  }  

O/P:

{ «бронирование»: [{ «Отметка времени окончания»: 1, «Идентификатор номера»: «1», «пользователь»: «abcd», «isAllDay»: true, «Идентификатор бронирования»: «1», «Отметка времени начала»: 1 }] }

Комментарии:

1. @фабрицио-проспери: Рад, что смог помочь 🙂