Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIButton event not handled 1% of the time: who should I blame in my responder chain?

My application tends to sometimes lose track of what responder should handle a touch event.

My situation:

  • a XIB file defining 3 views:
    • one view as the File's Owner's view
    • 2 extra views that are added to the view hierarchy programmatically
  • One of the subview (SubviewA) has a UIButton, configured to send the myAction: selector to the FirstResponder when a "Touch Up Inside" event is detected
  • SubviewA knows how to handle myAction:

99% of the time, everything goes fine. When the user taps the button, SubviewA takes care of the myAction: message and everything's fine. But from times to times, users complain that the button "freezes" and I actually reproduced it myself a couple of times without being able to find a clear scenario to make it happen on demand.

My investigation so far is:

  • when nothing happens when tapping the button:
    • my button detects the tap cause it gets highlighted when pressed
    • myAction: is not called on SubviewA
    • the rest of the UI remains responsive

The code I'm talking about is some legacy code I'm trying to fix. Having a view responding to an event for one of its subviews sounds like a weird architecture to me. So far, I've always used the File's Owner to take care of touch events so I pointed out the Responder Chain to be the ideal responsible for the bug. But I can't find why! From my understanding, as the button doesn't know how to handle the message and has no view controller attached to it, it should forward it to its superview (ButtonA, that knows how to handle it)!

My questions are :

  • any idea on where the bug might come from? (responder chain?)
  • any comment on whether a view should handle its button behaviors itself or if a view controller should do it?

Edit: I have an idea on how to fix the bug: wire the button action straight to SubviewA rather than using FirstResponder within Interface Builder. The reason why I posted this question is to try to understand why is the responder chain not working from times to times.

like image 334
Dirty Henry Avatar asked Nov 04 '22 05:11

Dirty Henry


2 Answers

Can you just make SubviewA becomeFirstResponder and then relinquish it when finished?

like image 142
Dan Avatar answered Nov 12 '22 19:11

Dan


When touches are handled in a subview, they generally aren't passed up the chain. So for example if you're catching touches in the view controller of the content view, you'll get touches on UILabel because it isn't catching them. Those events get passed to the content view and then to the controller. But you won't see any touches on UIButton since that class is catching them (remember UIButton interprets a number of touch sequences, not just touch-up-inside).

For this reason you'll need to subclass UIButton to see the touches. When you do that, be sure to always pass the events to the super class when you're done with them, else UIButton won't work correctly. See Subclassing Notes in the UIControl Class Reference. Also take a look at Control Events in that reference, as well as some of the instance methods to be sure you really need to catch the touches in your code. Note for example, that UIButton inherits the ability to track touches from UIControl.

like image 33
Kamar Shad Avatar answered Nov 12 '22 18:11

Kamar Shad