JSON 反序列化时 Swift 中的 SIGABRT 错误
SIGABRT error in Swift when JSON deserializing
我正在尝试制作一个有两个主要重点的 Swift 应用程序。一种是在 ScrollView 中显示来自 URL 的所有数据,另一种是用于获取游戏随机名称的按钮。
按钮有效,我得到一个随机游戏,但是当我尝试使用 UIScrollView
加载应用程序时,我在第 33 行收到 SIGABRT。
感谢任何帮助
编辑:我已经修复了 SIGABRT,但我似乎无法在 UIScrollView
中显示任何信息。现在有人在代码中看到任何明显的问题吗?
@IBOutlet weak var infoView: UIView!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var labelScroll: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
parseGame()
}
func parseGame() {
let url: URL = URL(string: "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name")!
print(url)
let responseData: Data? = try? Data(contentsOf: url)
if let responseData = responseData {
let json: Any? = try? JSONSerialization.jsonObject(with: responseData, options: [])
print(json ?? "Couldn't get JSON")
if let json = json {
let dictionary: [String: Any]? = json as? [String: Any]
if let dictionary = dictionary {
guard let result = dictionary["results"] as? [String:Any]? else { return }
if let result = result {
let name = result["name"] as? String?
if let name = name {
for i in 1...100 {
labelScroll.text = "Name: \(name)"
}
}
}
}
}
}
}
哦不!这是json解析死亡金字塔!
一个不错的小选择
如果您知道 json 您将收到的结构,您可以创建一些结构来为您的数据建模。 Swift 还有一个很酷的协议,称为“Codable”,它在解析 json 并将其转换为您在代码中创建的对象方面做了很多繁重的工作。
让我们对数据建模!
我们将创建 2 个符合 Codable 协议的结构。第一个将保存整个响应数据
struct ApiGameReponse:Codable {
var error:String
var limit:Int
var offset:Int
var pages:Int
var totalResults:Int
var status:Int
var version:String
var games:[Game]
private enum CodingKeys:String, CodingKey {
//The enum's rawValue needs to match the json's fieldName exactly.
//That's why some of these have a different string assigned to them.
case error
case limit
case offset
case pages = "number_of_page_results"
case totalResults = "number_of_total_results"
case status = "status_code"
case version
case games = "results"
}
}
和第二个结构来模拟我们的游戏对象。 (这是一个单一的字符串,是的,我知道非常令人兴奋......)因为这个特定的 json 数据代表一个只有 1 个名称的游戏 属性 我们真的不需要一个完整的结构,但是如果json 不同,据说有“gamePrice”和“genre”属性,一个结构会更好看。
struct Game:Codable {
var name:String
}
保持漂亮
很了解你,但我不喜欢看丑陋的代码。为了保持干净,我们将把函数 you 分成两部分。最好有一堆较小的 readable/reusable 函数,每个函数都完成一个任务,而不是 1 个 superSizeMe 数字 3 和一大杯可乐。
获取数据
第 1 部分:从 URL
获取数据
func getJSONData(_ urlString: String) -> Data? {
guard
let url:URL = URL(string: urlString),
let jsonData:Data = try? Data(contentsOf: url)
else { return nil }
return jsonData
}
第 2 部分:将数据解码成我们可以使用的东西
func getGameNames() -> [String] {
let apiEndpoint = "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name"
guard
let data = getJSONData(apiEndpoint),
let response = try? JSONDecoder().decode(ApiGameReponse.self, from: data)
else { return [] }
//Neat little function "map" allows us to create an array names from the array of game objects.
let nameArray = response.games.map { [=13=].name }
return nameArray
}
实施
最后我们可以获得名称并根据需要使用它们。
override func viewDidLoad() {
//I recommend putting this somewhere else
//Perhaps create a method called "setup()" and call it in this class's inializer.
let names = getGameNames()
print(names) //Implement the array of names as needed
}
我正在尝试制作一个有两个主要重点的 Swift 应用程序。一种是在 ScrollView 中显示来自 URL 的所有数据,另一种是用于获取游戏随机名称的按钮。
按钮有效,我得到一个随机游戏,但是当我尝试使用 UIScrollView
加载应用程序时,我在第 33 行收到 SIGABRT。
感谢任何帮助
编辑:我已经修复了 SIGABRT,但我似乎无法在 UIScrollView
中显示任何信息。现在有人在代码中看到任何明显的问题吗?
@IBOutlet weak var infoView: UIView!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var labelScroll: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
parseGame()
}
func parseGame() {
let url: URL = URL(string: "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name")!
print(url)
let responseData: Data? = try? Data(contentsOf: url)
if let responseData = responseData {
let json: Any? = try? JSONSerialization.jsonObject(with: responseData, options: [])
print(json ?? "Couldn't get JSON")
if let json = json {
let dictionary: [String: Any]? = json as? [String: Any]
if let dictionary = dictionary {
guard let result = dictionary["results"] as? [String:Any]? else { return }
if let result = result {
let name = result["name"] as? String?
if let name = name {
for i in 1...100 {
labelScroll.text = "Name: \(name)"
}
}
}
}
}
}
}
哦不!这是json解析死亡金字塔!
一个不错的小选择
如果您知道 json 您将收到的结构,您可以创建一些结构来为您的数据建模。 Swift 还有一个很酷的协议,称为“Codable”,它在解析 json 并将其转换为您在代码中创建的对象方面做了很多繁重的工作。
让我们对数据建模!
我们将创建 2 个符合 Codable 协议的结构。第一个将保存整个响应数据
struct ApiGameReponse:Codable {
var error:String
var limit:Int
var offset:Int
var pages:Int
var totalResults:Int
var status:Int
var version:String
var games:[Game]
private enum CodingKeys:String, CodingKey {
//The enum's rawValue needs to match the json's fieldName exactly.
//That's why some of these have a different string assigned to them.
case error
case limit
case offset
case pages = "number_of_page_results"
case totalResults = "number_of_total_results"
case status = "status_code"
case version
case games = "results"
}
}
和第二个结构来模拟我们的游戏对象。 (这是一个单一的字符串,是的,我知道非常令人兴奋......)因为这个特定的 json 数据代表一个只有 1 个名称的游戏 属性 我们真的不需要一个完整的结构,但是如果json 不同,据说有“gamePrice”和“genre”属性,一个结构会更好看。
struct Game:Codable {
var name:String
}
保持漂亮
很了解你,但我不喜欢看丑陋的代码。为了保持干净,我们将把函数 you 分成两部分。最好有一堆较小的 readable/reusable 函数,每个函数都完成一个任务,而不是 1 个 superSizeMe 数字 3 和一大杯可乐。
获取数据
第 1 部分:从 URL
获取数据func getJSONData(_ urlString: String) -> Data? {
guard
let url:URL = URL(string: urlString),
let jsonData:Data = try? Data(contentsOf: url)
else { return nil }
return jsonData
}
第 2 部分:将数据解码成我们可以使用的东西
func getGameNames() -> [String] {
let apiEndpoint = "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name"
guard
let data = getJSONData(apiEndpoint),
let response = try? JSONDecoder().decode(ApiGameReponse.self, from: data)
else { return [] }
//Neat little function "map" allows us to create an array names from the array of game objects.
let nameArray = response.games.map { [=13=].name }
return nameArray
}
实施
最后我们可以获得名称并根据需要使用它们。
override func viewDidLoad() {
//I recommend putting this somewhere else
//Perhaps create a method called "setup()" and call it in this class's inializer.
let names = getGameNames()
print(names) //Implement the array of names as needed
}