Segue 和使用 instantiateViewController 有啥区别?

Posted

技术标签:

【中文标题】Segue 和使用 instantiateViewController 有啥区别?【英文标题】:What is the difference between Segue and using instantiateViewController?Segue 和使用 instantiateViewController 有什么区别? 【发布时间】:2018-01-12 04:24:22 【问题描述】:

segue 和 instanceViewController 有什么区别?

我一直在试图弄清楚如何使用 segues 将图像从一个视图控制器发送到另一个视图控制器和 2 个答案(Passing Image to another View Controller (Swift) 和 How do I segue an image to another ViewController and display it within an ImageView?)都说要使用 segues,但是在尝试使用 segues 时我遇到了一些问题,例如照片库关闭后第二个视图控制器未显示或图像未显示。

转义示例

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.destination is XferImageViewController 
        print("Test: ", pickedImage.image)
        let xferVC = segue.destination as? XferImageViewController
        xferVC?.storedImage = pickedImage.image
    
    print("WHAT IS GOING ON")
//        if segue.destination is XferImageViewController 
//            let xferVC = segue.destination as? XferImageViewController
//            print(pickedImage.image)
//            //xferVC?.storedImage = pickedImage.image
//            xferVC?.storedImage = pickedImageVar
//        



func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage 
        pickedImage.image = image
     else 
        print("Something went wrong")
    
    let image = info[UIImagePickerControllerOriginalImage] as? UIImage
    dismiss(animated:true, completion: nil)
    performSegue(withIdentifier: "xferImage", sender: self)

InstantiateViewController 示例

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage 
        pickedImage.image = image
     else 
        print("Something went wrong")
    
    let image = info[UIImagePickerControllerOriginalImage] as? UIImage
    dismiss(animated:true, completion: nil)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "xferImage") as! XferImageViewController
    controller.storedImage = image
    present(controller, animated: true, completion: nil)

所以在使用 InstantiateViewController 而不是 segue 之后,我得到了我想要的结果。两者有什么区别? (我确定了那个 segue 标识符,尝试了 segue.destination 和 storyboard ID,但仍然没有得到我需要的东西)在照片库关闭呼叫后我可能不知道如何使用 segue,但仍然想知道区别。

【问题讨论】:

您在使用 segue 时是否在控制台上收到任何消息?如果是这样,请将该消息添加到问题中。 【参考方案1】:

问题在于,当您启动 segue 时,segue 会特别关注视图控制器层次结构的状态。您必须将performSegue(withIdentifier:sender:) 推迟到dismiss 完成,即将其放入dismiss 的完成句柄中:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage 
        pickedImage.image = image
     else 
        print("Something went wrong")
    

    dismiss(animated: true) 
        self.performSegue(withIdentifier: "xferImage", sender: self)
    

以上对我来说很好。

顺便说一句,您可以简化您的 prepare(for:sender:) 实现:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if let xferVC = segue.destination as? XferImageViewController 
        xferVC.storedImage = pickedImage.image
    


两个有些无关的观察结果:

    如果pickedImage 是图像视图,我建议将其重命名(并更新故事板中的出口)为pickedImageView。避免混淆 UIImage 属性和 UIImageView 出口是一个很好的约定。

    这是一个更次要的观察,但在Model-View-Controller 设计中,您通常不想依赖UIKit 对象,如UIImageView 来保存模型对象,即选定的图像。它暗示了“视图”对象和“模型”对象之间的概念混淆。另外,如果当前视图控制器没有 UIImageView 怎么办?

    我个人建议将所选图像存储在单独的 UIImage? 属性中:

    private var selectedImage: UIImage?
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
        if let image = info[UIImagePickerControllerOriginalImage] as? UIImage 
            selectedImage = image
    
            // if you also want to update a `UIImageView` in the current
            // view controller, fine, do that, but it shouldn't be confused
            // with the "model".
            //
            // pickedImageView.image = image
         else 
            print("Something went wrong")
        
    
        dismiss(animated: true) 
            self.performSegue(withIdentifier: "xferImage", sender: self)
        
    
    

    还有:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if let xferVC = segue.destination as? XferImageViewController 
            xferVC.storedImage = selectedImage
        
    
    

【讨论】:

作为补充说明,请确保 xferImage 是您的 segue 标识符,而不是 viewController 的标识符。由于代码通过使用与instantiateViewController 相同的标识符顺利运行,我猜你使用了viewController 的标识符而不是segue @Malik - 是的,我明白你的意思;您不想将 segue 标识符与视图控制器标识符混淆。幸运的是,如果你没有带有那个标识符的 segue,它会产生一个错误告诉你,所以它是相当明显的。但很好的澄清。 感谢您的深入解释和有用的提示!事实上,我确实在第一个控制器中有一个 UIImageView 用于测试目的。【参考方案2】:

尝试使用下面的函数

override func prepare(for segue: UIStoryboardSegue, sender: Any?)

    if segue.identifier == "segue"
    
        if let xferVC = segue.destination as? XferImageViewController 
            xferVC.storedImage = pickedImage.image

                //Why Optional here ?
                //xferVC?.storedImage = pickedImage.image
            
          
  

【讨论】:

以上是关于Segue 和使用 instantiateViewController 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

使用 segue 在 View Controller 之间传递变量

自定义 segue 和导航控制器动画故障

Segue 使用错误的动画和后退按钮未显示 [关闭]

返回按钮到另一个故事板

使用闭包和代理和Segue进行反向传值

使用带有情节提要参考的“Unwind Segue”时“没有标识符的segue”