-[UIApplication setStatusBarHidden:withAnimation]这个方法不会触发@"statusBarHidden"键的KVO通知。

6

我有一段代码在根视图控制器中,观察了-[UIApplication sharedApplication]@"statusBarHidden"属性,并根据其响应调整其视图的大小。

这样做时,会触发KVO通知:

[[UIApplication sharedApplication] setStatusBarHidden:YES]

但是当我这样做时,KVO通知不会被触发:
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide]

我需要在状态栏重新出现时调整视图大小,但我正在使用调用后者方法的第三方 API。

如何最好地处理这个问题?


我已经为此提交了一个错误报告: http://openradar.appspot.com/radar?id=2642401 - Mike Greiner
4个回答

3

背景

为什么您会看到通知触发的差异可能与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的选择器(与交换一起使用)。如果是这种情况,从字符串构建的选择器可以相当容易地混淆,以避免检测
无论如何,这只是一些选项...

3
我找到了一个解决方案:
  • 使用UIApplication的子类,比如MyUIApplication
  • 重写setStatusBarHidden:withAnimation方法,在调用super之后发送一个NSNotification
  • 在main.m文件中修改一行代码:return UIApplicationMain(argc, argv, @"MyUIApplication", NSStringFromClass([MyAppDelegate class]));

这样,当你设置状态栏隐藏状态时,你将会收到自定义通知。


1

提醒一下,这仅适用于对setStatusBarHidden等的显式调用。该代码不会针对UIViewController childViewControllerForStatusBarHidden机制隐藏状态栏而触发。 - Sean Langley
@SeanLangley 没想到那个。感谢您的反馈! - hfossli

0

你可以观察应用程序主窗口(或其子视图之一)的frame,或者重写某个视图的layoutSubviews方法。


1
主窗口的框架不会改变,它仍然是全屏状态。 - Mike Greiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接