Swift 5:为什么我的结构中的数据突然为空/零?
Swift 5: Why is my data within struct suddenly empty / nil?
更新:
我想知道的主要事情是,我能够在下载 JSON 功能成功后登录 self.schedule (.monday)
,但是当表应该是刷新了。
问题
目前在我的 ScheduleViewController
中有两个单独的 UITableViews,其中表格应该由视图控制器它的 downloadSchedule()
函数以不同的方式填充下载的数据。
URLSession
任务成功后,接收到的数据将存储在名为 json
的新变量中,然后在控制台中打印。一切正常。
现在,当 downloadSchedule()
函数完成它的请求并调用下一个重新加载表的函数时,我想计算 numberOfRowsInSection
的数据,但我得到一个 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an optional value
.
虽然这个变量之前是用下载的数据填充的,但是现在我要更新表格的时候突然空了。怎么会这样?
代码
我在 ScheduleViewController
中声明我的变量,如下所示:
var schedule: Schedule?
downloadSchedule()
函数在viewDidLoad()
之后执行:
func downloadSchedule(completed: @escaping () -> Void) {
let url = URL(string: "example.com/meta/schedule")
URLSession.shared.dataTask(with: url!) { data, _, error in
if error == nil {
do {
self.schedule = try JSONDecoder().decode(Schedule.self, from: data!)
DispatchQueue.main.async {
print("executed")
completed()
}
} catch {
print("JSON Error")
}
}
}.resume()
}
downloadSchedule {
self.mondayTableView.reloadData()
self.tuesdayTableView.reloadData()
}
首先更新表的示例:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
var count:Int?
if tableView == self.mondayTableView {
count = schedule?.monday.count
}
if tableView == self.tuesdayTableView {
count = schedule?.tuesday.count
}
return count!
}
这些是我的时间表和日期结构:
// MARK: - Schedule
struct Schedule: Codable {
let monday: [Day]
let tuesday: [Day]
let wednesday: [Day]
let thursday: [Day]
let friday: [Day]
let saturday: [Day]
let sunday: [Day]
let nextmonday: [Day]
let nexttuesday: [Day]
let nextwednesday: [Day]
let nextthursday: [Day]
let nextfriday: [Day]
let nextsaturday: [Day]
let nextsunday: [Day]
let airtimeAPIVersion: String
enum CodingKeys: String, CodingKey {
case monday, tuesday, wednesday, thursday, friday, saturday, sunday, nextmonday, nexttuesday, nextwednesday, nextthursday, nextfriday, nextsaturday, nextsunday
case airtimeAPIVersion = "AIRTIME_API_VERSION"
}
}
// MARK: - Day
struct Day: Codable {
let startTimestamp: String?
let endTimestamp: String?
let name: String?
let dayDescription: String?
let id: Int?
let instanceID: Int?
let instanceDescription: String?
let record: Int?
let url: String?
let imagePath: String?
let starts: String?
let ends: String?
enum CodingKeys: String, CodingKey {
case startTimestamp = "start_timestamp"
case endTimestamp = "end_timestamp"
case name = "name"
case dayDescription = "description"
case id = "id"
case instanceID = "instance_id"
case instanceDescription = "instance_description"
case record = "record"
case url = "url"
case imagePath = "image_path"
case starts = "starts"
case ends = "ends"
}
}
JSON
{
"monday": [
{
"start_timestamp": "2020-06-01 01:35:00",
"end_timestamp": "2020-06-01 01:37:37",
"name": "TEST",
"description": "",
"id": 174,
"instance_id": 950,
"instance_description": "",
"record": 0,
"url": "",
"image_path": "example.com/api/show-logo?id=174",
"starts": "2020-06-01 01:35:00",
"ends": "2020-06-01 01:37:37"
}
],
"tuesday": [
...
]
}
您从未将任何内容分配给 self.schedule
这两行:
let json = try JSONDecoder().decode(Schedule.self, from: data!)
print(json)
不要更改 self.schedule
的值。你需要写
self.schedule = try JSONDecoder().decode(Schedule.self, from: data!)
当你这样做时:JSONDecoder().decode(Schedule.self, from: data!)
这意味着 "data is a bunch of bytes that are JSON, parse it into a Schedule value and return it."
在那一行中,Schedule.self
是我们试图将其解析为的类型——它与 self.schedule
无关
你不应该在 tableView:numberOfRowsInSection
方法中 return 潜在的 nil。因为它应该在初始 tableview 加载数据时调用,并且 100% 你会崩溃。您可以 return 0
.
所以:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
guard let schedule = schedule else { return 0 }
var count:Int = 0
if tableView == self.mondayTableView {
count = schedule.monday.count
}
if tableView == self.tuesdayTableView {
count = schedule.tuesday.count
}
return count
}
还有,你确定
schedule.monday
或 . tuesday
loadData 后不是 nil 吗?
self.schedule
在tableView:numberOfRowsInSection
中是nil吗?
- 这个
UITableViewDelegate
你没有超过 2 个 tableView(在这个
viewcontroller)?
如果您收到 url 请求或解析 json 的错误,您的 loadData
中的完成处理程序也会更新调用。将 completed()
添加到此位置或将您的位置移至底部:
func downloadSchedule(completed: @escaping () -> Void) {
let url = URL(string: "https://api/....")
URLSession.shared.dataTask(with: url!) { data, _, error in
if error == nil,
let data = data {
do {
self.schedule = try JSONDecoder().decode(Schedule.self, from: data)
print("JSON \(self.schedule?.monday)")
} catch {
print("JSON Error")
}
}
DispatchQueue.main.async {
completed()
}
}.resume()
}
更新:
我想知道的主要事情是,我能够在下载 JSON 功能成功后登录 self.schedule (.monday)
,但是当表应该是刷新了。
问题
目前在我的 ScheduleViewController
中有两个单独的 UITableViews,其中表格应该由视图控制器它的 downloadSchedule()
函数以不同的方式填充下载的数据。
URLSession
任务成功后,接收到的数据将存储在名为 json
的新变量中,然后在控制台中打印。一切正常。
现在,当 downloadSchedule()
函数完成它的请求并调用下一个重新加载表的函数时,我想计算 numberOfRowsInSection
的数据,但我得到一个 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an optional value
.
虽然这个变量之前是用下载的数据填充的,但是现在我要更新表格的时候突然空了。怎么会这样?
代码
我在 ScheduleViewController
中声明我的变量,如下所示:
var schedule: Schedule?
downloadSchedule()
函数在viewDidLoad()
之后执行:
func downloadSchedule(completed: @escaping () -> Void) {
let url = URL(string: "example.com/meta/schedule")
URLSession.shared.dataTask(with: url!) { data, _, error in
if error == nil {
do {
self.schedule = try JSONDecoder().decode(Schedule.self, from: data!)
DispatchQueue.main.async {
print("executed")
completed()
}
} catch {
print("JSON Error")
}
}
}.resume()
}
downloadSchedule {
self.mondayTableView.reloadData()
self.tuesdayTableView.reloadData()
}
首先更新表的示例:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
var count:Int?
if tableView == self.mondayTableView {
count = schedule?.monday.count
}
if tableView == self.tuesdayTableView {
count = schedule?.tuesday.count
}
return count!
}
这些是我的时间表和日期结构:
// MARK: - Schedule
struct Schedule: Codable {
let monday: [Day]
let tuesday: [Day]
let wednesday: [Day]
let thursday: [Day]
let friday: [Day]
let saturday: [Day]
let sunday: [Day]
let nextmonday: [Day]
let nexttuesday: [Day]
let nextwednesday: [Day]
let nextthursday: [Day]
let nextfriday: [Day]
let nextsaturday: [Day]
let nextsunday: [Day]
let airtimeAPIVersion: String
enum CodingKeys: String, CodingKey {
case monday, tuesday, wednesday, thursday, friday, saturday, sunday, nextmonday, nexttuesday, nextwednesday, nextthursday, nextfriday, nextsaturday, nextsunday
case airtimeAPIVersion = "AIRTIME_API_VERSION"
}
}
// MARK: - Day
struct Day: Codable {
let startTimestamp: String?
let endTimestamp: String?
let name: String?
let dayDescription: String?
let id: Int?
let instanceID: Int?
let instanceDescription: String?
let record: Int?
let url: String?
let imagePath: String?
let starts: String?
let ends: String?
enum CodingKeys: String, CodingKey {
case startTimestamp = "start_timestamp"
case endTimestamp = "end_timestamp"
case name = "name"
case dayDescription = "description"
case id = "id"
case instanceID = "instance_id"
case instanceDescription = "instance_description"
case record = "record"
case url = "url"
case imagePath = "image_path"
case starts = "starts"
case ends = "ends"
}
}
JSON
{
"monday": [
{
"start_timestamp": "2020-06-01 01:35:00",
"end_timestamp": "2020-06-01 01:37:37",
"name": "TEST",
"description": "",
"id": 174,
"instance_id": 950,
"instance_description": "",
"record": 0,
"url": "",
"image_path": "example.com/api/show-logo?id=174",
"starts": "2020-06-01 01:35:00",
"ends": "2020-06-01 01:37:37"
}
],
"tuesday": [
...
]
}
您从未将任何内容分配给 self.schedule
这两行:
let json = try JSONDecoder().decode(Schedule.self, from: data!)
print(json)
不要更改 self.schedule
的值。你需要写
self.schedule = try JSONDecoder().decode(Schedule.self, from: data!)
当你这样做时:JSONDecoder().decode(Schedule.self, from: data!)
这意味着 "data is a bunch of bytes that are JSON, parse it into a Schedule value and return it."
在那一行中,Schedule.self
是我们试图将其解析为的类型——它与 self.schedule
你不应该在 tableView:numberOfRowsInSection
方法中 return 潜在的 nil。因为它应该在初始 tableview 加载数据时调用,并且 100% 你会崩溃。您可以 return 0
.
所以:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
guard let schedule = schedule else { return 0 }
var count:Int = 0
if tableView == self.mondayTableView {
count = schedule.monday.count
}
if tableView == self.tuesdayTableView {
count = schedule.tuesday.count
}
return count
}
还有,你确定
schedule.monday
或. tuesday
loadData 后不是 nil 吗?self.schedule
在tableView:numberOfRowsInSection
中是nil吗?- 这个
UITableViewDelegate
你没有超过 2 个 tableView(在这个 viewcontroller)?
如果您收到 url 请求或解析 json 的错误,您的 loadData
中的完成处理程序也会更新调用。将 completed()
添加到此位置或将您的位置移至底部:
func downloadSchedule(completed: @escaping () -> Void) {
let url = URL(string: "https://api/....")
URLSession.shared.dataTask(with: url!) { data, _, error in
if error == nil,
let data = data {
do {
self.schedule = try JSONDecoder().decode(Schedule.self, from: data)
print("JSON \(self.schedule?.monday)")
} catch {
print("JSON Error")
}
}
DispatchQueue.main.async {
completed()
}
}.resume()
}