cellForRow(at: indexPath) returns nil 并使我的 swift 应用程序崩溃
cellForRow(at: indexPath) returns nil and crashes my swift app
在我的 swift
应用程序中,我在 UITableView
中显示单元格,前 10 个单元格包含一张照片。我决定为每个单元格添加视差效果,这样当用户上下滚动 table - 图像会改变它的偏移量。
这就是我从网络服务中获取数据并将其最初添加到 table 视图的方式:
func makePostQueryForFetchingData(_ parameters: [String:AnyObject], url: String, type: String)
{
Alamofire.request(url, method: .post, parameters: (parameters), encoding: JSONEncoding.default)
.validate()
.responseJSON { response in
switch response.result {
case .success:
DispatchQueue.main.async(execute: {
items.removeAllObjects()
tview.reloadData()
if let jsonData = response.result.value as? [[String: AnyObject]] {
for singleJSON in jsonData {
if let single = SingleNode.fromJSON(JSON(singleJSON)){
self.items.add(single)
}
}
}
self.refreshController.endRefreshing()
print("before crash")
self.tview.reloadData()
print("end")
})
case .failure(let error):
print(error)
}
}
}
当我 运行 这个功能在启动时 - 一切正常。但是,如果我向下滚动 table 然后快速向上滚动并拉动以刷新 - 应用程序崩溃。
在下拉刷新中,我从上面调用函数。
处理视差效果的函数如下所示:
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tview) {
for indexPath in self.tview.indexPathsForVisibleRows! {
if (indexPath.row < 10) {
print(indexPath)
print(self.tview.cellForRow(at: indexPath))
self.setCellImageOffset(cell: self.tview.cellForRow(at: indexPath) as! BigDetailsOnListCell, indexPath: indexPath as NSIndexPath)
}
}
}
}
我意识到,当我快速向上滚动 table 并刷新它时 - 我在控制台中看到:
before crash
0
nil
fatal error: unexpectedly found nil while unwrapping an Optional value
那么为什么 self.tview.cellForRow(at: indexPath)
returns 为零?
cellForRow(at:)
只会 return 如果 table 视图当前有该行的可见单元格。如果没有可见单元格,它不会调用您的 table 视图的数据源方法来获取单元格,它会 return nil
。
您需要处理 cellForRow(at:)
可能 return 为零的事实。不要强行打开它。使用条件解包。与 indexPathsForVisibleRows
类似;也没有充分的理由强制展开该值。
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tview) {
if let visiblePaths = self.tview.indexPathsForVisibleRows {
for indexPath in visiblePaths {
if (indexPath.row < 10) {
if let cell = self.tview.cellForRow(at: indexPath as? BigDetailsOnListCell) {
self.setCellImageOffset(cell: cell, indexPath: indexPath as NSIndexPath)
}
}
}
}
}
在 pullToRefresh 方法中将 yourArray 设为 nil,当您收到响应时它会填充新数据。
indexPathsForVisibleRows
中的索引不向您保证该单元格已显示。注意 "visible row" 和 "displayed cell" 之间的区别。可见行意味着滚动位置使得该行显示或将显示。它基于可见性计算。另一方面 cellForRow(at:)
基于当前添加为子视图的单元格。
直到单元格实际显示出来cellForRow(at:)
还可以returnnil
.
这可能会在调用 reloadTable()
或滚动时立即发生。
我不知道这是否对任何人有帮助,但对我来说很重要。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.view = nil
}
这段代码解决了我的问题。我在发送新版本后立即遇到了一个问题。问题是这个错误迫使应用程序在这行代码处崩溃:
let guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? YourCustomTableViewCell else {...}
我发现崩溃总是在我尝试快速切换视图时发生(我能够切换视图,因为它们在标签栏控制器中)。
在我的 swift
应用程序中,我在 UITableView
中显示单元格,前 10 个单元格包含一张照片。我决定为每个单元格添加视差效果,这样当用户上下滚动 table - 图像会改变它的偏移量。
这就是我从网络服务中获取数据并将其最初添加到 table 视图的方式:
func makePostQueryForFetchingData(_ parameters: [String:AnyObject], url: String, type: String)
{
Alamofire.request(url, method: .post, parameters: (parameters), encoding: JSONEncoding.default)
.validate()
.responseJSON { response in
switch response.result {
case .success:
DispatchQueue.main.async(execute: {
items.removeAllObjects()
tview.reloadData()
if let jsonData = response.result.value as? [[String: AnyObject]] {
for singleJSON in jsonData {
if let single = SingleNode.fromJSON(JSON(singleJSON)){
self.items.add(single)
}
}
}
self.refreshController.endRefreshing()
print("before crash")
self.tview.reloadData()
print("end")
})
case .failure(let error):
print(error)
}
}
}
当我 运行 这个功能在启动时 - 一切正常。但是,如果我向下滚动 table 然后快速向上滚动并拉动以刷新 - 应用程序崩溃。
在下拉刷新中,我从上面调用函数。
处理视差效果的函数如下所示:
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tview) {
for indexPath in self.tview.indexPathsForVisibleRows! {
if (indexPath.row < 10) {
print(indexPath)
print(self.tview.cellForRow(at: indexPath))
self.setCellImageOffset(cell: self.tview.cellForRow(at: indexPath) as! BigDetailsOnListCell, indexPath: indexPath as NSIndexPath)
}
}
}
}
我意识到,当我快速向上滚动 table 并刷新它时 - 我在控制台中看到:
before crash
0
nil
fatal error: unexpectedly found nil while unwrapping an Optional value
那么为什么 self.tview.cellForRow(at: indexPath)
returns 为零?
cellForRow(at:)
只会 return 如果 table 视图当前有该行的可见单元格。如果没有可见单元格,它不会调用您的 table 视图的数据源方法来获取单元格,它会 return nil
。
您需要处理 cellForRow(at:)
可能 return 为零的事实。不要强行打开它。使用条件解包。与 indexPathsForVisibleRows
类似;也没有充分的理由强制展开该值。
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tview) {
if let visiblePaths = self.tview.indexPathsForVisibleRows {
for indexPath in visiblePaths {
if (indexPath.row < 10) {
if let cell = self.tview.cellForRow(at: indexPath as? BigDetailsOnListCell) {
self.setCellImageOffset(cell: cell, indexPath: indexPath as NSIndexPath)
}
}
}
}
}
在 pullToRefresh 方法中将 yourArray 设为 nil,当您收到响应时它会填充新数据。
indexPathsForVisibleRows
中的索引不向您保证该单元格已显示。注意 "visible row" 和 "displayed cell" 之间的区别。可见行意味着滚动位置使得该行显示或将显示。它基于可见性计算。另一方面 cellForRow(at:)
基于当前添加为子视图的单元格。
直到单元格实际显示出来cellForRow(at:)
还可以returnnil
.
这可能会在调用 reloadTable()
或滚动时立即发生。
我不知道这是否对任何人有帮助,但对我来说很重要。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.view = nil
}
这段代码解决了我的问题。我在发送新版本后立即遇到了一个问题。问题是这个错误迫使应用程序在这行代码处崩溃:
let guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? YourCustomTableViewCell else {...}
我发现崩溃总是在我尝试快速切换视图时发生(我能够切换视图,因为它们在标签栏控制器中)。