0

This is an odd issue because sometimes the code works fine and others times it crashes. But lately it's only been crashing.

I have an image that I'm getting from a uiview. I grab the image using the capture function below then send the image to a property to go to prepareForSegue to be sent to the next view controller. The code keeps crashing when it's time to return the image. I debugged it and saw the property definitely went from nil to containing the image however when it's time to segue it crashes. But the crash is within the capture function not the segue. It's weird because the image is returned (debugger showed it) but the capture return is where the crash keeps happening. The crash happens on:

//This seems to be the main problem
return capturedImage

and here's the crash log for the returned capturedImage

Thread1: EXC_BAD_INSTRUCTION (code=EXC_1336_INVOP, subcode=0x0)

I was also getting crashes on this line but somehow the crashes stopped. I can't put a crash log for this one because it stopped crashing but I don't know why or how it stopped

view!.layer.renderInContext(UIGraphicsGetCurrentContext()!)

Any ideas?

Btw I use a storyboard button to trigger the segue.

class MainController: UIViewController {

@IBOutlet weak var mainView: UIView!

var mainPic: UIImage? 


override func viewDidLoad() {
        super.viewDidLoad()
}

//MARK: -Func to convert image in uiview to uiimage
//get image from UIView, render it for Retina compatibility, then return it as an UIImage
func captureAndRenderUIImageFromUIView(view:UIView?) -> UIImage {

    UIGraphicsBeginImageContextWithOptions((view?.bounds.size)!, true, 0.0)
    view!.drawViewHierarchyInRect(view!.bounds, afterScreenUpdates: true)

    //I was also getting crashes on this line but they stopped??
    view!.layer.renderInContext(UIGraphicsGetCurrentContext()!)
    let capuredImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    //The return value is where the crash keeps happening
    return capturedImage
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

     self.mainPic = self.captureAndRenderUIImageFromUIView(mainView)

     if segue.identifier == "toDetailController"{

     let detailVC = segue.destinationViewController as! DetailController
     detailVC.detailPic = self.mainPic!
    }
 }

}

}

Here's the view it's going to

class DetailController: UIViewController {
@IBOutlet weak var imageView: UIImageView!

var detailPic: UIImage? 

override func viewDidLoad() {
     super.viewDidLoad()
     self.imageView.image = self.detailPic
   }

}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • Don't keep up guessing. What's the error? Update your question with exact and complete details of the crash. – rmaddy Sep 11 '16 at 21:48
  • @maddy oh yeah your right, i'll update it now – Lance Samaria Sep 11 '16 at 21:55
  • @maddy updated it thanks – Lance Samaria Sep 11 '16 at 22:00
  • There should be much more to the error. Are you able to reproduce the crash in the debugger? – rmaddy Sep 11 '16 at 22:01
  • I just tried. When the debugger gets to the crash line the only thing that shows is the crash line I updated with. The debugger itself is blank. – Lance Samaria Sep 11 '16 at 22:04
  • Try print it out and see if it have any value or not, it also can be happened by thing on other thread, so make sure check that out also – Tj3n Sep 12 '16 at 03:56
  • @Tj3n Good idea. I tried it. I can print out the value in the mainPic property which means the capturedImage is getting the data and passing it off. But when it comes time to print the capturedImage property it crashes. If it's thread issue any idea what you think it could be? – Lance Samaria Sep 12 '16 at 09:27
  • @Tj3n I just noticed I put the capturedImage print statement in the wrong place. It does print so the image is definitely being grabbed and returned. Now the issue is even more perplexing, hmmmmmm – Lance Samaria Sep 12 '16 at 09:39

1 Answers1

0

Hi there: I started out trying to do things in much the same way you've tried to here; however, it is error prone and unstable. I recently discovered that you can save yourself a lot of hassle by using the UIView method snapshotViewAfterScreenUpdates. Simply call this directly on the view you want to take a snapshot of and it will return a UIImage.

You can see more detail at: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/snapshotViewAfterScreenUpdates:

In fact I've learned something here too as there appears to be a family of these functions (e.g. a function which gives you a resizeable UIImageView).

Hope that helps.

EDIT: In one of my apps I implemented this through a subroutine as follows:

func getSnapshot(target: UIView) -> Void {
            // Clean down
            if let _ = self.snapshotView where self.snapshotView.isDescendantOfView(self) {
                self.snapshotView.removeFromSuperview()
            }

            self.snapshotView = target.snapshotViewAfterScreenUpdates(true)
            let snapshotFrame : CGRect = CGRect(origin: recognizer.locationInView(self), size: target.frame.size)
            self.snapshotView.frame = snapshotFrame
            self.addSubview(self.snapshotView)

            self.canMoveSnapshot = true
        }
Marcus
  • 2,153
  • 2
  • 13
  • 21
  • thanks for the help, I'm looking at the docs now. Why did you say the code is error prone? What were the problems you discovered? – Lance Samaria Sep 12 '16 at 09:29
  • The short answer is that it just didn't work so well (!). However, I think that when you are working with a lot of views, trying to isolate the portion of the screen that you want to capture to get the correct CGContext can be time-consuming and prone to errors. The function I've suggested takes care of all of that for you in one method call. – Marcus Sep 12 '16 at 10:08
  • I looked up the method on the doc link you sent and it seems to return a view object. How did you get it to go from a view object to an image object? func snapshotViewAfterScreenUpdates(_ afterUpdates: Bool) -> UIView – Lance Samaria Sep 12 '16 at 10:19
  • Can you upload the code you used to manage that? I read this post that says your supposed to use 'drawViewHierarchyInRec'. http://stackoverflow.com/questions/20203682/uiimage-from-a-uiview-created-with-snapshotviewafterscreenupdates – Lance Samaria Sep 12 '16 at 10:46
  • Apologies for the confusion. The method does indeed return a UIView rather than a UIImageView. The UIView's contents, however, contain a rendered image of the view that you have asked for a snapshot of. I've added my code in my original answer above. You can accomplish what you want with drawViewHierarchyInRect but I think if at all possible you should try to use snapshotAfterScreenUpdates as it is the more "current" approach. – Marcus Sep 12 '16 at 10:50
  • thanks for the help, I appreciate it.Maybe i'm missing something here but how didd you convert it to an image? – Lance Samaria Sep 12 '16 at 11:02
  • I didn't actually need to use the underlying image in my case - in my implementation I kept track of which object had been long-pressed and then passed that to the second view controller once the image had been dragged to a certain region of the screen. Having looked around a bit it appears that it is problematic getting an image out of a view obtained through the snapshot method (technicaly it returns a UIReplicantView). If you need the image and don't want to use my methodology then drawViewHierarchyInRect is probably your best bet after all. – Marcus Sep 12 '16 at 11:25
  • @ Sparky Thanks I appreciate it the help. I used it in the method above and that seems to be what everyone suggests. Now I just need to find out why it isn't working. Enjoy your day! – Lance Samaria Sep 12 '16 at 11:38