背景
为什么您会看到通知触发的差异可能与KVO的工作原理有关。 您观察了一个属性的值。 在这种情况下,是statusBarHidden
。 但是,为了获得通知,该属性必须通过存在的setter进行更改。
通知不能神奇地发生,因此它需要被编码为setter的副作用。 (通常在编写属性时,自动为您完成此操作)但是,具有该属性的类还可以选择直接修改ivar。 在这种情况下,UIApplication
拥有/曾经拥有一个内部结构_applicationFlags
,其中包含
unsigned int statusBarHidden:1;
因此,
setStatusBarHidden:withAnimation:
很可能只是直接修改底层数据成员,绕过了需要回调观察者的 setter 方法。
解决方案?
就你而言,你没有提到这个应用程序是否为应用商店(可能是个人/业余爱好、企业应用程序或越狱应用程序)。
可能适合你的一件事情是使用
方法混淆来替换
setStatusBarHidden:withAnimation:
的默认实现为你自己的实现。 你自己的实现可以简单地调用
setStatusBarHidden:
,这将重新启用 KVO。 或者,如果您想保留动画,您可能可以使用 GCD 安排
setStatusBarHidden:
在
setStatusBarHidden:withAnimation:
完成动画所需的时间后运行。 这样,您仍然会获得动画,并且还会通过调用
setStatusBarHidden:
触发 KVO。
我不确定方法交换是否总是被拒绝在App Store应用中。我认为它是(至少在iOS框架中交换方法时),但根据这个
链接,它要么被允许,要么可以通过。
下一个问题是,“如果方法交换确实是苹果想要避免的东西,尽管它
在公共API中存在,有没有一种方法可以规避它?”
除非
我链接到的Stack Overflow问题中的人在撒谎,否则看起来它确实通过了审核(至少有时)。因此,可能没有以自动化方式进行测试。也许有时会被人工测试人员
可视化识别出,他们会看到标准功能以不同的方式工作,从而推断出这必须是方法交换的结果。在这种情况下,您实际上不想使用它来更改状态栏UI行为,只是要抓住通知,所以这不应该对他们造成麻烦。
或者,他们可能正在寻找已知iOS API的选择器(与交换一起使用)。如果是这种情况,从字符串构建的选择器可以相当容易地混淆,以
避免检测。
无论如何,这只是一些选项...