It seems that when the view is removed from the window, it is separated from any touches associated with it. Therefore, when the contact finally ends, the system does not send touchesEnded:… or touchesCancelled:… to the view.
Workaround by disabling tab switching
If you just want to turn off tab switching when you click a button, you can do this by giving the tab bar controller a delegate and returning the delegate NO from tabBarController:shouldSelectViewController: For example, in your test application, you can FirstViewController delegate the controller of the tab bar:
- (void)viewWillAppear:(BOOL)animated { self.tabBarController.delegate = self; }
And the view controller can allow the tab bar controller to select the tab only when the button is not pressed (highlighted):
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { return !_button.highlighted; }
Workaround when detecting backlight reset button to NO
When a button is removed from the window, it resets the highlighted property to NO . Thus, one common way to get around this problem is to use key value monitoring (KVO) to monitor the state of the button (instead of relying on the button to send you actions). Configure yourself as an observer for the highlighted button property as follows:
static int kObserveButtonHighlightContext; - (void)viewDidLoad { [super viewDidLoad]; [_button addObserver:self forKeyPath:@"highlighted" options:NSKeyValueObservingOptionOld context:&kObserveButtonHighlightContext]; } - (void)dealloc { [_button removeObserver:self forKeyPath:@"highlighted" context:&kObserveButtonHighlightContext]; }
During testing, I found that the button sends an extra KVO notification when it is removed from the window before it resets the highlighted property back to NO . Therefore, when processing a KVO notification, make sure that the value has really changed:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == &kObserveButtonHighlightContext) { if ([change[NSKeyValueChangeOldKey] boolValue] != _button.highlighted) { [self updatePlaybackForButtonState]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
Finally, start or stop playback according to the highlighted button property:
- (void)updatePlaybackForButtonState { if (_button.highlighted) { NSLog(@"start playback"); } else { NSLog(@"end playback"); } }