Home>
I want to clear the error and pass the value

I am in the process of creating an original application, but I am having trouble because I cannot pass a value to the previous screen with UINavigationController.
I want to pass the value of UIImage to MainViewController when saveButton is pressed, but I get an Unexpectedly found nil while unwrapping an Optional value error and it falls.

Thanks for your response.

Unexpectedly found nil while unwrapping an Optional value
Applicable source code
import UIKit
import FSCalendar

class MainViewController: UIViewController, FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {

    @IBOutlet weak var calendar: FSCalendar!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var piechartImageResultView: UIImageView!
    var piechartImageResult: UIImage!
    override func viewDidLoad () {
        super.viewDidLoad ()
        self.calendar.dataSource = self
        self.calendar.delegate = self
        piechartImageResultView.image = piechartImageResult
    }

// Process when the date on the calendar is tapped
    func calendar (_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        let tmpDate = Calendar (identifier: .gregorian)
        let year = tmpDate.component (.year, from: date)
        let month = tmpDate.component (.month, from: date)
        let day = tmpDate.component (.day, from: date)
        dateLabel.text = ("\ (year). \ (month). \ (day)")

    }



    override func prepare (for segue: UIStoryboardSegue, sender: Any?) {
           if segue.identifier == "toAddPiechart" {
               let nextView = segue.destination as! AddPiechartViewController
            nextView.dateResult = dateLabel.text!
           }
       }

}
Applicable source code
import UIKit
class AddPiechartViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var pieChartView: UIView!
    @IBOutlet weak var categoryPicker: UIPickerView!
    @IBOutlet weak var startTimeLabel: UILabel!
    @IBOutlet weak var endTimeLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var piechartImageView: UIView!

    var dateResult = ""
    var pickerDataList = ["unselected", "sleep", "study", "work", "meal", "play", "exercise"]
    var pickerColor: [UIColor] = [.white, .blue, .red, .brown, .orange, .green, .gray]
    var selectedPickerColor: UIColor = .whitevar startRadian = 0.0
    var endRadian = 0.0
    var piechartImage: UIImage?


    override func viewDidAppear (_ animated: Bool) {
        super.viewDidAppear (animated)
        if isMovingToParent {
            let grayPath = UIBezierPath ()
            grayPath.addArc (withCenter: CGPoint (x: pieChartView.frame.width/2, y: pieChartView.frame.height/2), // center
                radius: self.pieChartView.frame.height/5, // radius r
                startAngle: 0.0, // start angle
                endAngle: .pi * 2, // end angle
                clockwise: true) // clockwise
            let grayLayer = CAShapeLayer ()
            grayLayer.path = grayPath.cgPath
            grayLayer.fillColor = UIColor.clear.cgColor // fill color in the middle
            grayLayer.strokeColor = UIColor.white.cgColor // stroke color
            grayLayer.lineWidth = 40.0 // line width
            self.pieChartView.layer.addSublayer (grayLayer)
        }
    }

    override func viewDidLoad () {
        super.viewDidLoad ()

        categoryPicker.delegate = self
        categoryPicker.dataSource = self
        dateLabel.text = dateResult

    }

    // UIPickerView delegate
    func numberOfComponents (in pickerView: UIPickerView)->Int {
        return 1
    }
    func pickerView (_ pickerView: UIPickerView, numberOfRowsInComponent component: Int)->Int (
        return pickerDataList.count
    }
    func pickerView (_ pickerView: UIPickerView,
                    titleForRow row: Int,
                    forComponent component: Int)->String? (
        return pickerDataList [row]
    }
    // Get color by selecting PickereView
    func pickerView (_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) (
        selectedPickerColor = pickerColor [row]
    }

    @IBAction func startTimeSlider (_ sender: UISlider) {
        let startSliderValue = Int (sender.value)
        startRadian = Double (startSliderValue)
        if startSliderValue% 2 == 0 {
            startTimeLabel.text = "\ (startSliderValue/2): 00"
        } else {
            startTimeLabel.text = "\ (startSliderValue/2): 30"
        }
    }@IBAction func endTimeSlider (_ sender: UISlider) {
        let startSliderValue = Int (sender.value)
        endRadian = Double (startSliderValue)
        if startSliderValue% 2 == 0 {
            endTimeLabel.text = "\ (startSliderValue/2): 00"
        } else {
            endTimeLabel.text = "\ (startSliderValue/2): 30"
        }
    }
    @IBAction func addButton (_ sender: UIButton) {
        let timeRadian = .pi * 2.0/48.0
        let grayPath = UIBezierPath ()
        grayPath.addArc (withCenter: CGPoint (x: self.pieChartView.frame.width/2, y: self.pieChartView.frame.height/2), // center
            radius: self.pieChartView.frame.height/5, // radius r
            startAngle: CGFloat (.pi * -0.5 + startRadian * timeRadian), // start angle
            endAngle: CGFloat (.pi * -0.5 + endRadian * timeRadian), // end angle
            clockwise: true) // clockwise
        let grayLayer = CAShapeLayer ()
        grayLayer.path = grayPath.cgPath
        grayLayer.fillColor = UIColor.clear.cgColor // fill color in the middle
        grayLayer.strokeColor = selectedPickerColor.cgColor // stroke color
        grayLayer.lineWidth = 40.0 // line width
        self.pieChartView.layer.addSublayer (grayLayer)
    }
    @IBAction func saveButton (_ sender: UIButton) {
        piechartImage = piechartImageView.toImage ()
        let nvc = self.presentingViewController as! UINavigationController
        let index = nvc.viewControllers.count-2
        let vc = nvc.viewControllers [index] as! MainViewController
        vc.piechartImageResult = self.piechartImage
        self.navigationController? .popViewController (animated: true)
    }
}
Applicable source code
import Foundation
import UIKit
/// UIView extension (image)
public extension UIView {
    func toImage ()->UIImage {
        UIGraphicsBeginImageContextWithOptions (self.bounds.size, false, 0.0)
        guard let context = UIGraphicsGetCurrentContext () else {
            print ("could not get the current context.")
            return UIImage ()
        }
        self.layer.render (in: context)
        guard let image = UIGraphicsGetImageFromCurrentImageContext () else (
            print ("The view could not be converted to an image.")
            return UIImage ()
        }
        UIGraphicsEndImageContext ()
        return image
    }
}
What I tried

I want to pass piechartImage when saveButton at the bottom of AddpiechartViewController is pressed, but I don't know how to pass it to a value that does not use segue.

Supplemental information (FW/tool version, etc.)

Please provide more detailed information here.

  • Answer # 1

    presentingViewControllerThe value is entered only in the modal transition (displayed as present) from the previous View.

    presentingViewContrller

    In this case,presentingViewController Isnil However, I think that I got a runtime error because I forced downcast it.

    If you write only the outline, I think that the value will be entered in the property of the transition source class with the following feeling.

    @IBAction func saveButton (_ sender: UIButton) {
            // presentingViewController is used only when transitioning from present to present
            // let nvc = self.presentingViewController as! UINavigationController
            if let index = navigationController? .viewControllers.count {
                let vc = navigationController? .viewControllers [index -2] as? MainViewController
                // assignment
                vc? .piechartImageResult = ....
            }
            self.navigationController? .popViewController (animated: true)
        }

Related articles