IOS, UIView, Detect Hidden State Change in Subview

ort11 picture ort11 · Jun 11, 2013 · Viewed 7.9k times · Source

Is there anyway to detect a hidden state change (or other change) in a sub view in a UIView (not UIViewController). Would like to detect this async somehow.

There are reasons for my madness.

Answer

herzbube picture herzbube · Jun 11, 2013

You can use KVO (key value observing) to detect a change to the value of the property hidden.

Add your observer (self in this example) in the following way:

UIView* viewToObserve = [self getViewToObserve];  // implement getViewToObserve
[viewToObserve addObserver:self forKeyPath:@"hidden" options:0 context:NULL];

Now add the following method to your observer class:

- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
  UIView* viewToObserve = [self getViewToObserve];
  if (object == viewToObserve)
  {
    if ([keyPath isEqualToString:@"hidden"])
    {
      // react to state change
    }
  }
}

The observer method will be invoked whenever the hiddenproperty changes its value. If I am not mistaken, the method will be invoked synchronously in the context of the thread that makes the change to the property. If you need asynchronous notification you can add that yourself, for instance by using one of the NSObject methods performSelector:withObject:afterDelay: or performSelector:onThread:withObject:waitUntilDone:.

BTW: You don't need the checks in the observer method, obviously, if you only observe a single object and/or property. I left the checks in for illustration purposes. I also recommend reading Apple's documentation on KVO and KVC (key value coding) to understand what's going on here.

The runtime happily continues notifying your observer even if the observer is deallocated - resulting in an application crash! So don't forget to remove the observer before it is de-allocated, at the latest this should happen in the observer's dealloc:

- (void) dealloc
{
    UIView* viewToObserve = [self getViewToObserve];
    [viewToObserve removeObserver:self forKeyPath:@"hidden"];
    [super dealloc];
}