3D Touch, peek and pop is crashing with a fatal error : unexpectedly found nil while unwrapping an Optional value
3D Touch, peek and pop is crashing with a fatal error : unexpectedly found nil while unwrapping an Optional value
编辑:
我有一个包含 2 个单元格的 tableView,我正在尝试使用 3DTouch 实现 Peek & Pop。
- 2 个单元格通过 modalView 重定向到 2 个不同的视图控制器
- 当用户点击第一个视图控制器上的单元格时,我将数据发送到第二个视图控制器
- 当用户在第二个视图控制器中选择一个单元格时,模态视图被关闭,数据被发送回第一个视图控制器
我设法使每个单独的单元格都可以查看并与其他单元格相比将其提升,但是一旦我想要弹出它并重定向到其他视图控制器,我的应用程序就会崩溃
这是我的第一个代码VC:
我在 viewDidLoad 中注册预览:
if( traitCollection.forceTouchCapability == .available){
registerForPreviewing(with: self, sourceView: self.tableView)
}
然后我通过实施 2 种方法来遵守协议 UIViewControllerPreviewingDelegate
:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView?.indexPathForRow(at: location) else { return nil }
previewingContext.sourceRect = tableTest.rectForRow(at: indexPath)
let sb = UIStoryboard(name: "Main", bundle: nil)
guard let detailVC = sb.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return nil }
return detailVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit :UIViewController) {
show(viewControllerToCommit, sender: self)
}
在func tableView(...didSelectRowAt)
中:
if (indexPath.row == 0) {
guard let controller = storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return }
controller.titlePassed = cell?.textLabel?.text
controller.variableIn2ndVC = theVariabletoSend
controller.anotherVarIn2nd = theVariabletoSend2
...
...
navigationController?.present(controller, animated: true, completion: nil)
}
我的第二个视图控制器代码:
var titlePassed: String?
var variableIn2ndVC: String?
var anotherVarIn2nd: String?
...
...
@IBAction func cancelButton(_ sender: AnyObject) {
self.dismiss(animated: true, completion: nil)
}
...
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 && titlePassed == "FROM" {
return 1
} else {
return Stations.count
}
}
public func numberOfSections(in tableView: UITableView) -> Int {
if titlePassed == "FROM" {
return 2
} else {
return 1
}
}
在didSelectRowAt
中,我有一些回调将一些数据发送到第一个控制器
当用户点击单元格时,我抓取 textLabel
中的文本并使用 callBack
将其发送到第一个 VC
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 && titlePassed == "FROM" {
let stringToSendBack = cell?.textLabel!.text
// put str in callBack in order to access it in the 1st VC
callBack?(str!)
dismiss(animated: true, completion: nil)
}
我想你已经解决了,但我只是总结一下你已经得出的结论,仅供记录。
让我们暂时忽略 peek 和 pop。然后,当您通常响应用户对单元格的点击从主控制器转到细节控制器 (DestinationViewController) 时,您可以这样做(代码缩写):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let controller = storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return }
controller.titlePassed = cell?.textLabel?.text
controller.variableIn2ndVC = theVariabletoSend
controller.anotherVarIn2nd = theVariabletoSend2
navigationController?.present(controller, animated: true, completion: nil)
}
到目前为止,还不错。现在让我们来看看图片。这是一个完全不同的情况[=42=]。您像这样创建导航控制器(再次缩写):
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
let sb = UIStoryboard(name: "Main", bundle: nil)
guard let detailVC = sb.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return nil }
return detailVC
}
看出区别了吗?
在第一种情况下,您正在创建 DestinationViewController 并配置它。
在第二种情况下,您正在创建 DestinationViewController 但完全忽略了配置它。因此,它是未配置的,它的所有属性都是 nil
.
这个事实后来以某种方式赶上了你,并导致了崩溃。
如果你想先查看然后弹出,也就是说,在 3D 触摸之后呈现 DestinationViewController,就像用户只是点击单元格时一样,你必须做 一切 如果用户 只是点击了单元格,你会这样做。您可以在两个 UIViewControllerPreviewingDelegate 方法中的任何一个中执行此操作,但是如果您在第一个方法中没有这样做,则必须肯定在第二个方法中执行此操作,因为实际上是那个方法呈现视图控制器。否则你将呈现一个损坏的视图控制器(如你所知)。
因此,总而言之,您的问题是由 tableView(_:didSelectRowAt)
和两个 UIViewControllerPreviewingDelegate 方法以某种方式交织在一起的假设引起的。他们不是。这是两种 完全不同的情况 — 用户点击,或用户 3D 按下。您需要为其中的 每个 创建和配置视图控制器的完整实现。
编辑:
我有一个包含 2 个单元格的 tableView,我正在尝试使用 3DTouch 实现 Peek & Pop。
- 2 个单元格通过 modalView 重定向到 2 个不同的视图控制器
- 当用户点击第一个视图控制器上的单元格时,我将数据发送到第二个视图控制器
- 当用户在第二个视图控制器中选择一个单元格时,模态视图被关闭,数据被发送回第一个视图控制器
我设法使每个单独的单元格都可以查看并与其他单元格相比将其提升,但是一旦我想要弹出它并重定向到其他视图控制器,我的应用程序就会崩溃
这是我的第一个代码VC: 我在 viewDidLoad 中注册预览:
if( traitCollection.forceTouchCapability == .available){
registerForPreviewing(with: self, sourceView: self.tableView)
}
然后我通过实施 2 种方法来遵守协议 UIViewControllerPreviewingDelegate
:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView?.indexPathForRow(at: location) else { return nil }
previewingContext.sourceRect = tableTest.rectForRow(at: indexPath)
let sb = UIStoryboard(name: "Main", bundle: nil)
guard let detailVC = sb.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return nil }
return detailVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit :UIViewController) {
show(viewControllerToCommit, sender: self)
}
在func tableView(...didSelectRowAt)
中:
if (indexPath.row == 0) {
guard let controller = storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return }
controller.titlePassed = cell?.textLabel?.text
controller.variableIn2ndVC = theVariabletoSend
controller.anotherVarIn2nd = theVariabletoSend2
...
...
navigationController?.present(controller, animated: true, completion: nil)
}
我的第二个视图控制器代码:
var titlePassed: String?
var variableIn2ndVC: String?
var anotherVarIn2nd: String?
...
...
@IBAction func cancelButton(_ sender: AnyObject) {
self.dismiss(animated: true, completion: nil)
}
...
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 && titlePassed == "FROM" {
return 1
} else {
return Stations.count
}
}
public func numberOfSections(in tableView: UITableView) -> Int {
if titlePassed == "FROM" {
return 2
} else {
return 1
}
}
在didSelectRowAt
中,我有一些回调将一些数据发送到第一个控制器
当用户点击单元格时,我抓取 textLabel
中的文本并使用 callBack
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 && titlePassed == "FROM" {
let stringToSendBack = cell?.textLabel!.text
// put str in callBack in order to access it in the 1st VC
callBack?(str!)
dismiss(animated: true, completion: nil)
}
我想你已经解决了,但我只是总结一下你已经得出的结论,仅供记录。
让我们暂时忽略 peek 和 pop。然后,当您通常响应用户对单元格的点击从主控制器转到细节控制器 (DestinationViewController) 时,您可以这样做(代码缩写):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let controller = storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return }
controller.titlePassed = cell?.textLabel?.text
controller.variableIn2ndVC = theVariabletoSend
controller.anotherVarIn2nd = theVariabletoSend2
navigationController?.present(controller, animated: true, completion: nil)
}
到目前为止,还不错。现在让我们来看看图片。这是一个完全不同的情况[=42=]。您像这样创建导航控制器(再次缩写):
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
let sb = UIStoryboard(name: "Main", bundle: nil)
guard let detailVC = sb.instantiateViewController(withIdentifier: "DestinationViewController") as? DestinationViewController else { return nil }
return detailVC
}
看出区别了吗?
在第一种情况下,您正在创建 DestinationViewController 并配置它。
在第二种情况下,您正在创建 DestinationViewController 但完全忽略了配置它。因此,它是未配置的,它的所有属性都是
nil
.
这个事实后来以某种方式赶上了你,并导致了崩溃。
如果你想先查看然后弹出,也就是说,在 3D 触摸之后呈现 DestinationViewController,就像用户只是点击单元格时一样,你必须做 一切 如果用户 只是点击了单元格,你会这样做。您可以在两个 UIViewControllerPreviewingDelegate 方法中的任何一个中执行此操作,但是如果您在第一个方法中没有这样做,则必须肯定在第二个方法中执行此操作,因为实际上是那个方法呈现视图控制器。否则你将呈现一个损坏的视图控制器(如你所知)。
因此,总而言之,您的问题是由 tableView(_:didSelectRowAt)
和两个 UIViewControllerPreviewingDelegate 方法以某种方式交织在一起的假设引起的。他们不是。这是两种 完全不同的情况 — 用户点击,或用户 3D 按下。您需要为其中的 每个 创建和配置视图控制器的完整实现。