JSON 写入崩溃中的另一个无效顶级类型
Another Invalid top-level type in JSON write crash
所以,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'
下面是模型,错误集中在顶层类型,这是怎么回事?它只是 Array 的 RoooBooking 实例,符合 Codable,那又怎样?
有人知道我做错了什么吗?将不胜感激!
// 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
) -> RoomBookings {
return RoomBookings(
bookings: bookings ?? self.bookings
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> 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
) -> 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 -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> 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() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}
尝试
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:
{ "bookings": [{ "endTimestamp": 1, "roomId": "1", "user":
"abcd", "isAllDay": true, "bookingId": "1", "startTimestamp": 1
}] }
所以,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'
下面是模型,错误集中在顶层类型,这是怎么回事?它只是 Array 的 RoooBooking 实例,符合 Codable,那又怎样?
有人知道我做错了什么吗?将不胜感激!
// 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
) -> RoomBookings {
return RoomBookings(
bookings: bookings ?? self.bookings
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> 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
) -> 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 -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> 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() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}
尝试
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:
{ "bookings": [{ "endTimestamp": 1, "roomId": "1", "user": "abcd", "isAllDay": true, "bookingId": "1", "startTimestamp": 1 }] }