Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS 9 - UIButton on subview does not fire IBAction outlet

I've been struggling with this for a couple of days now and haven't been able to pinpoint the cause of my problem, as the title says, a UIButton on a subview is not firing the IBAction outlet when "clicked".

Let me elaborate, I'm working on a "tinder-like" app, where I'm using this third party library. I'm implementing customized views which have buttons and other controllers in them. The buttons in these "Cards" are not firing their IBAction outlets.

As far as I can tell, the library does the following:

Stacks 3 "DraggableViews" on top of each other, each draggable view has 2 child views, one is the content view, where my custom view lives, and the other is an overlay view, which has an image view on top. The draggable views use two gesture recognizer to do its thing, the first one is a tap gesture that calls a delegate method to handle tap events in the card (in their example its used to show a browser view). The second gesture is a pan gesture used to implement the swipe functionality of the card.

I've done my homework and have tried a few different solutions but I can't get the IBAction to fire. I've tried the following:

  • Use the parent view of the DraggableViews to disable the gesture recognizer when the touch event is triggered on a button. - This works (gesture is disabled) but the IBAction is not fired. on the case of the pan gesture, I am no longer able to "swipe" the card when touching the button and the tap event does not hit a breakpoint in the delegate method mentioned above. In the UI, my button reacts to the touch as it animates, but its outlet in the view controller fails to hit a breakpoint. I've disabled this as so:

    //- Called when each DraggableView is visible (not called for view at index 0, but works alright for debugging in the mean time)
    func koloda(koloda: KolodaView, didShowCardAtIndex index: UInt) {
     let subviews = koloda.subviews
     for subview in subviews {
        if let recognizers = subview.gestureRecognizers {
            for gesture in recognizers {
                if gesture is UIPanGestureRecognizer || gesture is UITapGestureRecognizer{
                    //- Also tried setting this to false but nothing.
                    gesture.cancelsTouchesInView = false 
                    gesture.delegate = self
                }
            }
        }
    }
    
    //- On the gestureRecognizerDelegate
    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
       if touch.view is UIButton {
         return false
       } else {
         return true
       }
    }
    
  • Implemented a tap gesture on the button programmatically, On viewDidLoad I add the action to the tap gesture but this does not trigger the outlet either.

  • Programmatically set the userInteractionEnabled property of the ImageView to True hoping that this will allow the touch event to go through the responder chain (although I read in another post that this would have the opposite effect?).

I've also checked in the storyboard that all the relevant views and controllers in my custom view have the userInteractionEnabled option enabled.

I don't know if its relevant, but my custom view lives in a xib file, when I pass the view to the library I do it by instantiating the view controller and passing passing over its view, as so:

if let vc = spiViewConntroller {
        return vc.view
    }

Any help or suggestions would be greatly appreciated!

Cheers!

EDIT: Continuing with my search for truth, I've completely removed the overlay view from the library, inspecting my custom views on the UI debugger i can see that the overlay view and its ImageView are no longer there. The button still does not fire its outlet so I can assume that the overlay view is not causing this issue.

I've forked the Koloda library and created a branch with a demo example, the branch name is "StackOverflowDemo". I've added a custom view with one button, I've created two outlets in its view controller where I'm changing the title of the button (which works) on view did load. I've also disabled the two gestures on the button to replicate what i've currently got in my app. If you do clone this down you'll need to swipe the first card off as the card at index 0 wont have the gestures disabled.

I'll keep digging, hopefully someone can pinpoint what I'm doing wrong!

Cheers.

like image 901
Daniel Ormeño Avatar asked Mar 21 '16 09:03

Daniel Ormeño


1 Answers

Daniel. Your issue is that you don't add your view controller as child to view controller which operates with Koloda. In the result your vc.view is shown, because Koloda retains it, but nobody retains your view controller, so you are losing important lifecycle methods and it gets deallocated.

The approach your trying to use is called Container View Controller. Apple has suggestion about its implementation here: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html

Simple implementation here:

- (void) displayContentController: (UIViewController*) content {
   [self addChildViewController:content];
   content.view.frame = [self frameForContentController];
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];
}
like image 192
Eugene Andreyev Avatar answered Sep 25 '22 14:09

Eugene Andreyev