1

I have a class where I am calling the UIImagePickerController to select an image and return it so I can use it somewhere else in my code.

Now I set the delegate and implement the necessary function I need, but the delegate functions aren't being called.

The portion of my code that has the issue:

import UIKit

typealias PhotoTakingHelperCallback = (UIImage? -> Void)

class PhotoTakingHelper: NSObject
{

    weak var viewController:UIViewController!
    var callback: PhotoTakingHelperCallback
    var imagePickerController: UIImagePickerController?

    init(viewController:UIViewController , callback:PhotoTakingHelperCallback) {

        self.viewController = viewController

        self.callback = callback
        super.init()
        showPhotoSourceSelection()
    }


    func showPhotoSourceSelection() {
        let alertController = UIAlertController(title: nil, message: "Where do you want to get your picture from?", preferredStyle: .ActionSheet)

        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)

        alertController.addAction(cancelAction)

        let photoLibraryAction = UIAlertAction(title: "Photo from Library", style: .Default) { (action) -> Void in
            self.showImagePickerController(.PhotoLibrary)
        }

        alertController.addAction(photoLibraryAction)

        if (UIImagePickerController.isCameraDeviceAvailable(.Rear) ) {
            let cameraAction = UIAlertAction(title: "Photo from Camera", style: .Default, handler: { (action) -> Void in
                self.showImagePickerController(.Camera)
            })

            alertController.addAction(cameraAction)
        }

        viewController.presentViewController(alertController, animated: true, completion: nil)

    }

    func showImagePickerController(sourceType: UIImagePickerControllerSourceType) {
        imagePickerController = UIImagePickerController()
        imagePickerController!.delegate = self
        imagePickerController!.sourceType = sourceType

        print("Set the delegate \(imagePickerController?.delegate?.isMemberOfClass(PhotoTakingHelper))")

        self.viewController.presentViewController(imagePickerController!, animated: true, completion: nil)
    }

}


extension PhotoTakingHelper: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        print("HELLO?")
    }

    func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {

        viewController.dismissViewControllerAnimated(false, completion: nil)
        print("calling the callback now " )

        callback(image)

        print("Finished calling the callback")
    }


}

I've checked iPhone: UIImagePickerControllerDelegate methods not Invoked? and a similar problem and many more but none have solved the issue.

I've realized that none of the delegate methods are invoked as when I run through the program on the simulator and choose an image in the photo library, the console only prints.

Set the delegate Optional(true)

2
  • I think your imagePickerController is released before the delegate method call...just try to make it global...i mean declare as property Commented Oct 29, 2015 at 5:00
  • yes i do but i don't have it in the code sample , ill add it now to prevent confusion Commented Oct 29, 2015 at 16:36

1 Answer 1

8
+50

You're creating a PhotoTakingHelper but you're not keeping a reference to it. That is, you're doing something like this:

// In your view controller

@IBAction func pickImageButtonWasTapped() {
    _ = PhotoTakingHelper(viewController: self) { image in
        print("Callback!")
    }
}

The UIImagePickerController keeps only a weak reference to its delegate, which is not enough to keep it alive, so you have to keep a strong reference to it. You could do it by storing the helper in an instance variable of your view controller, like this:

// In your view controller

var helper: PhotoTakingHelper?

@IBAction func pickImageButtonWasTapped() {
    helper = PhotoTakingHelper(viewController: self) { image in
       print("Callback!")
    }
}

Or you could make the helper keep a reference to itself, like this:

// In PhotoTakingHelper

var me: PhotoTakingHelper?

init(viewController:UIViewController , callback:PhotoTakingHelperCallback) {
    self.viewController = viewController
    self.callback = callback
    super.init()
    me = self
    showPhotoSourceSelection()
}

And then you need to set the reference to nil when the image picker is done, to let the helper be deallocated:

extension PhotoTakingHelper: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        viewController.dismissViewControllerAnimated(false, completion: nil)
        callback(info[UIImagePickerControllerOriginalImage] as? UIImage)
        me = nil
    }

    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        viewController.dismissViewControllerAnimated(false, completion: nil)
        me = nil
    }

}
Sign up to request clarification or add additional context in comments.

3 Comments

Hey @rob , haven't tested the code yet but I was wondering if you can send me any links that further explains why the delegate has a weak reference and the whole strong/weak referencing because I find it really confusing ! THANKS!!
I was having the same issue. fixed it by making PhotoTakingHelper a class property of my view controller. Thanks @robmayoff

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.