背景
至于为什么您会在通知触发中看到这种差异,这可能与 KVO 的工作方式有关。您观察 property 的值。在这种情况下,statusBarHidden。但是,为了获得通知,该属性必须已通过为其存在的 setter 进行了更改。
通知不会神奇地发生,因此它实际上需要被编码为 setter 的副作用。 (这通常在对属性进行编码时自动为您完成)但是,具有该属性的类也可以选择直接修改 ivar。在这种情况下,UIApplication 有一个内部结构 _applicationFlags,其中包含
unsigned int statusBarHidden:1;
因此,setStatusBarHidden:withAnimation: 完全有可能只是直接修改底层数据成员,从而绕过回调观察者所需的 setter。
解决方案?
就您的解决方法而言,您没有提及此应用是否适用于应用商店(可能出于个人/爱好目的,可能是企业应用,也可能是越狱应用)。
可能适合您的一件事是使用method swizzling 将setStatusBarHidden:withAnimation: 的默认实现替换为您自己的实现。您自己的实现可以简单地调用setStatusBarHidden:,然后重新启用KVO。或者,如果您想保留动画,您可以使用 GCD 安排 setStatusBarHidden: 在 setStatusBarHidden:withAnimation: 完成动画所需的时间之后运行。这样,您仍然可以获得动画,并且还可以通过调用 setStatusBarHidden: 触发 KVO。
我不清楚 App Store 应用程序中是否总是拒绝方法调配。我认为是(至少,在 iOS 框架中调配方法时),但according to this, it is either allowed, or can slip through。
下一个问题是,“如果 Apple 确实希望您避免方法混用,尽管它being in public APIs,有没有办法解决这个问题?”
除非the Stack Overflow question I linked to 中的人在撒谎,否则它看起来确实通过了审查(至少有时是这样)。所以,也许它没有以自动化的方式进行测试。也许有时人类测试人员会在视觉上识别,他们认为标准功能的工作方式不同,他们推断一定是方法混搭的结果。在这种情况下,您实际上并不想使用它来更改状态栏 UI 行为,而只是为了锁定通知,因此不应该打扰他们。
或者,他们可能正在搜索已知 iOS API 的选择器(与 swizzling 一起使用)。如果是这种情况,从字符串构建的选择器很容易被混淆,to avoid detection。
无论如何,只是一些选择......