Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

-[UIApplication setStatusBarHidden:withAnimation] does not fire KVO notifications for @"statusBarHidden" key

Tags:

ios

uikit

I have code in my root view controller that observes the @"statusBarHidden" property of -[UIApplication sharedApplication] and adjusts its view's size in response.

When I do this, a KVO notification is fired:

[[UIApplication sharedApplication] setStatusBarHidden:YES]

But when I do this, a KVO notification is not fired:

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]

I need to resize my view when the status bar reappears but I'm using a third-party API that invokes the latter method.

What would be the best way to handle this?

like image 974
Mike Greiner Avatar asked Dec 05 '12 19:12

Mike Greiner


3 Answers

Background

As far as why you see this discrepancy in notifications firing, it probably has to do with how KVO works. You observe the value of a property. In this case, statusBarHidden. But, in order to get notifications, that property must have been changed by way of the setter that exists for it.

Notifications can't happen magically, so it effectively needs to be coded as a side-effect of the setter. (this is often done for you automatically, when coding your properties) However, the class that has that property could also choose to modify an ivar directly. In this case, UIApplication has/had an internal struct _applicationFlags, which contains

    unsigned int statusBarHidden:1;

So, it's entirely possible that setStatusBarHidden:withAnimation: is just modifying the underlying data member directly, which bypasses the setter needed to callback your observer.

Solution?

In terms of workarounds for you, you don't mention whether this app is for the app store or not (could be for personal/hobby purposes, could be an Enterprise app, or could be a jailbreak app).

One thing that might be an option for you is to use method swizzling to replace the default implementation of setStatusBarHidden:withAnimation: with one of your own. Your own implementation could simply call setStatusBarHidden:, which would then re-enable KVO. Or, if you wanted to keep the animation, you could probably use GCD to schedule setStatusBarHidden: to run after the amount of time it takes setStatusBarHidden:withAnimation: to finish animating. That way, you'd still get the animation, and also have the KVO triggered by calling setStatusBarHidden:.

It's not clear to me whether method swizzling is always rejected in App Store apps. I thought it was (at least, when swizzling methods in iOS frameworks), but according to this, it is either allowed, or can slip through.

The next question would be, "if method swizzling really is something Apple wants you to avoid, despite it being in public APIs, is there a way to work around that?"

Unless the people in the Stack Overflow question I linked to were lying, it looks like it does get through review (at least sometimes). So, maybe it's not tested for in an automated way. Maybe it's sometimes visually recognized by human testers, who see a standard feature working differently, in a way that they deduce must be a result of method swizzling. In this case, you don't actually want to use it to change the status bar UI behavior, just to latch on to a notification, so that shouldn't bother them.

Or, they might be searching for selectors for known iOS APIs (used with swizzling). If that's the case, selectors built from strings can pretty easily be obfuscated, to avoid detection.

Anyway, just some options ...

like image 103
Nate Avatar answered Nov 06 '22 13:11

Nate


I found a solution for this:

  • Subclass UIApplication with let's say MyUIApplication
  • Override setStatusBarHidden:withAnimation to call super and send a NSNotification when called
  • Change the line in main.m to return UIApplicationMain(argc, argv, @"MyUIApplication", NSStringFromClass([MyAppDelegate class]));

you'll get the custom notification you sent when you set status bar hidden state

like image 39
Or Arbel Avatar answered Nov 06 '22 12:11

Or Arbel


Based on Or Arbel's answer I wrote this class which sends a notification for your convinience.

https://gist.github.com/hfossli/6767765

like image 22
hfossli Avatar answered Nov 06 '22 11:11

hfossli