3

I'm trying to create a UIBarButtonItem that opens the camera once the button has been tapped. For some reason, my takePicture(_sender:) function doesn't seem to be getting called.

I originally tried to create my UIBarButtonItem using the Interface Builder. Here was the interface and a screenshot of the actions connected to the UIBarButtonItem: Image of the DetailViewController that contains my UIBarButtonItem

Image of the action outlets for my UIBarButtonItem

And here is the code for my takePicture(_sender:) function:

@IBAction func takePicture(_ sender: UIBarButtonItem) {

    print("Taking picture...")

    let imagePicker = UIImagePickerController()

    // If the device has a camera, take a picture; otherwise,
    // just pick from photo library
    if UIImagePickerController.isSourceTypeAvailable(.camera) {
        imagePicker.sourceType = .camera
    } else {
        imagePicker.sourceType = .photoLibrary
    }

    imagePicker.delegate = self

    // Place image picker on the screen
    present(imagePicker, animated: true, completion: nil)
}

The little circle next to my function declaration is filled in and connected properly:

Image of the connection to my @IBOutlet in the code.

However, when I load the simulator and press the button, the UIImagePickerController never appears and my print() function is never called in the code.

So, I then tried to declare the UIBarButtonItem programmatically to see if perhaps it was an issue under-the-hood of Xcode's Interface Builder. Here was my code:

(Note: I deleted the UIBarButtonItem from the Interface Builder and then I connected the UIToolbar to my code using an @IBOutlet.)

override func viewDidLoad() {
    super.viewDidLoad()

    let takePictureBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.camera, target: self, action: #selector(DetailViewController.takePicture))

    toolBar.setItems([takePictureBarButton], animated: false)
}

@objc func takePicture() {

    print("Taking picture...")

    let imagePicker = UIImagePickerController()

    // If the device has a camera, take a picture; otherwise,
    // just pick from photo library
    if UIImagePickerController.isSourceTypeAvailable(.camera) {
        imagePicker.sourceType = .camera
    } else {
        imagePicker.sourceType = .photoLibrary
    }

    imagePicker.delegate = self

    // Place image picker on the screen
    present(imagePicker, animated: true, completion: nil)
}

As a last ditch attempt at debugging this program and trying to find where the problem lies, I created a temporary button in my UI and connected that to my takePicture(_sender:) function instead (I changed the signature from a UIBarButtonItem to a UIButton). That worked perfectly. This tells me that the problem is not with the function itself, but has something to do with the connection.

Mattkx4
  • 199
  • 3
  • 16

3 Answers3

4

I was seconds away from posting this question when I found a similar question. The user stated that the root of their problem lied in a UITapGestureRecognizer on their View Controller.

To solve my problem, I simply set my UITapGestureRecognizer's target to be my StackView instead of the the entire view.

Original:

Image of my UITapGestureRecognizer's outlet collections.

Resolved:

Image of my UITapGestureRecognizer's outlet collections after the fix.

I'd be curious to learn why the UITapGestureRecognizer stopped my UIBarButtonItem from being tapped, but not the normal UIButton. Seems a little strange...

Mattkx4
  • 199
  • 3
  • 16
2

Swift 4

I went through this problem and referenced above answers. The project I worked on had UIButton as navigation bar item and hence it comes under navigation item and I found out that the outlet for the IBAction should be connected to the button in the bar button item rather than connecting it to the bar button item itself. In mattkx4's question, the IBAction has 'UIBarButtonItem' as its sender. I fixed the issue by connecting the button inside the bar button item to the action.

button_inside_bar_button_item

As you can see there is a button inside the bar button item. Connect the action to this button and the action will be triggered.

0

make sure you connect your camera button with action for touchUpInside event

Irshad Ahmad
  • 1,363
  • 11
  • 17
  • If I was trying to connect the action to a UIButton, that would be a valuable piece of advice. However, a UIBarButtonItem doesn't have a touchUpInside event. UIBarButtonItem is a subclass of UIBarItem which is a subclass of NSObject. Whereas a UIButton is a subclass of UIControl which contains all the touchUpInside() actions. Might want to check the documentation more carefully: - https://developer.apple.com/documentation/uikit/uicontrolevents - https://developer.apple.com/documentation/uikit/uibaritem - https://developer.apple.com/documentation/uikit/uibarbuttonitem – Mattkx4 Jul 03 '17 at 16:50