Segue和使用instantiateViewController有什么区别?

4

segue和instantiateViewController有什么区别?

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

Segue示例

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)
}

实例化视图控制器示例

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,但仍然无法得到我需要的结果)可能是因为我不知道如何在照片库dismiss调用后使用segue,但我仍然想知道它们的区别。


你在使用segue时有没有在控制台上收到任何消息?如果有,请将该消息添加到问题中。 - Fahri Azimov
2个回答

4
问题在于当您初始化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
    }
}

两个有些不相关的观察:
  1. If pickedImage is an image view, I'd suggest renaming it (and updating the outlets in your storyboard) to pickedImageView. It's a good convention to avoid confusion between UIImage properties and UIImageView outlets.

  2. This is an even more minor observation, but in Model-View-Controller design, you generally don't want to rely on UIKit objects, like UIImageView to hold model objects, namely the selected image. It suggests a conceptual confusion between "view" objects and "model" objects. Plus, what if the current view controller didn't have a UIImageView?

    I'd personally suggest storing the selected image in a separate UIImage? property:

    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)
        }
    }
    

    And:

    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
@Malik - 是的,我明白你的意思;你不想混淆segue标识符和视图控制器标识符。幸运的是,如果你没有使用该标识符的segue,它会生成一个告诉你这个错误,所以这将是相当明显的。但是很好的澄清。 - Rob
感谢您深入的解释和有用的提示!事实上,我在第一个控制器中为了测试目的确实有一个UIImageView。 - LampPost

0

尝试使用以下函数

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
            }
        }  
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接