Search code examples
iosswiftuiscrollviewdelegatesuiscrollviewdelegate

Using delegates: unexpectedly found nil while unwrapping an Optional value


I have two ViewControllers, assume one is named MainVC and the other one is named GetCameraRollImageViewController. In the second one, there is a UIScrollView which holds a UIImageView, since I'm using segue to show the second view controller, I've to use its delegate in the MainVC:

class ViewController: UIViewController, GetTextDelegate, GetCameraRollImageDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate  {
//
//other codes
//
    @IBAction func setNewImageFromCameraRoll(segue:UIStoryboardSegue)    {
        if let newImageVC = segue.sourceViewController as? GetCameraRollImageViewController{

            var scale:CGFloat = 1.0/newImageVC.scrollView.zoomScale;
            var visibleRect:CGRect!
            visibleRect.origin.x = newImageVC.scrollView.contentOffset.x * scale;
            visibleRect.origin.y = newImageVC.scrollView.contentOffset.y * scale;
            visibleRect.size.width = newImageVC.scrollView.bounds.size.width * scale;
            visibleRect.size.height = newImageVC.scrollView.bounds.size.height * scale;
            var cr:CGImageRef = CGImageCreateWithImageInRect(newImageVC.inputImage.image?.CGImage,visibleRect)
            var cropped:UIImage = UIImage(CGImage: cr)!
            imageView.image = cropped
        }
    }
}

The GetCameraRollImageViewController code:

import UIKit

protocol GetCameraRollImageDelegate{
    //
}

class GetCameraRollImageViewController: UIViewController, UIScrollViewDelegate {

    var delegate:GetCameraRollImageDelegate? = nil
    var inputImageDelegate:UIImage!

    @IBOutlet var scrollView: UIScrollView!
    @IBOutlet var inputImage:UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.scrollView.minimumZoomScale = 0.5
        self.scrollView.maximumZoomScale = 6.0
        self.scrollView.contentSize = self.inputImage.frame.size;
        self.scrollView.delegate = self
        inputImage.image = inputImageDelegate
}
    func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
        return self.inputImage
    }

}

But when I trigger setNewImageFromCameraRoll() it crashes the app with this error:

fatal error: unexpectedly found nil while unwrapping an Optional value

Note: Bothe scrollView and inputImage are bounded, and I'm not reading them in the viewDidLoad(), when they are empty.

enter image description here


Solution

  • [Updated based on comments]

    The line

    var visibleRect:CGRect!
    

    assigns visibleRect to nil and thus the subsequent line of

    visibleRect.origin.x = newImageVC.scrollView.contentOffset.x * scale;
    

    will then dereference visibleRect, find nil and produce the exception. You need to allocate a CGRect and assign it to visibleRect.

    [Original Answer]

    Is visibleRect bound? It doesn't look to be. If that is bound, then you'll notice other uses of !... You need to bind your outlets (typically in InterfaceBuilder):

    @IBOutlet var scrollView: UIScrollView!
    @IBOutlet var inputImage:UIImageView!
    

    Perhaps scrollView is not bound and thus, because it is implicitly unwrapped (the ! operator), when you reference it as nil your program will fatal.

    Use:

    var visibleRect = 
      CGRectMake (newImageVC.scrollView.contentOffset.x * scale,
                  newImageVC.scrollView.contentOffset.y * scale,
                  newImageVC.scrollView.bounds.size.width * scale,
                  newImageVC.scrollView.bounds.size.height * scale)