6

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

当我这样做时,会触发一个 KVO 通知:

[[UIApplication sharedApplication] setStatusBarHidden:YES]

但是当我这样做时,不会触发 KVO 通知:

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

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

处理这个问题的最佳方法是什么?

4

4 回答 4

3

背景

至于为什么您会在通知触发中看到这种差异,这可能与 KVO 的工作方式有关。你观察一个属性的值。在这种情况下,statusBarHidden。但是,为了获得通知,该属性必须通过为其存在的设置器进行更改。

通知不会神奇地发生,因此需要将其有效地编码为 setter 的副作用。(这通常在对属性进行编码时自动为您完成)但是,具有该属性的类也可以选择直接修改ivar。在这种情况下,UIApplication有/有一个内部结构_applicationFlags,其中包含

    unsigned int statusBarHidden:1;

因此,完全有可能setStatusBarHidden:withAnimation:只是直接修改底层数据成员,这绕过了回调观察者所需的设置器。

解决方案?

就您的解决方法而言,您没有提及此应用程序是否适用于应用程序商店(可能是出于个人/爱好目的,可能是企业应用程序,也可能是越狱应用程序)。

您可能会选择的一件事是使用方法调配setStatusBarHidden:withAnimation:来用您自己的方法替换默认实现。您自己的实现可以简单地调用setStatusBarHidden:,然后重新启用 KVO。或者,如果您想保留动画,您可以使用 GCD 安排在完成动画setStatusBarHidden:所需的时间之后运行。setStatusBarHidden:withAnimation:这样,您仍然可以获得动画,并且还可以通过调用来触发 KVO setStatusBarHidden:

我不清楚 App Store 应用程序中是否总是拒绝方法调配。我认为是(至少,在 iOS 框架中混合方法时),但据此,它要么是允许的,要么可以通过.

下一个问题是,“如果方法调配真的是 Apple 希望你避免的事情,尽管它在公共 API中,有没有办法解决这个问题?”

除非我链接到的 Stack Overflow 问题中的人在撒谎,否则它看起来确实通过了审查(至少有时是这样)。所以,也许它没有以自动化的方式进行测试。也许它有时会被人类测试人员视觉识别,他们认为标准功能的工作方式不同,他们推断一定是方法混搭的结果。在这种情况下,您实际上并不想使用它来更改状态栏 UI 行为,只是为了锁定通知,因此不应该打扰他们。

或者,他们可能正在搜索已知 iOS API 的选择器(与 swizzling 一起使用)。如果是这种情况,从字符串构建的选择器很容易被混淆,以避免检测

无论如何,只是一些选择......

于 2013-01-28T08:21:05.350 回答
3

我找到了一个解决方案:

  • 子类 UIApplication 让我们说 MyUIApplication
  • 覆盖setStatusBarHidden:withAnimation调用 super 并在调用时发送 NSNotification
  • 将 main.m 中的行更改为return UIApplicationMain(argc, argv, @"MyUIApplication", NSStringFromClass([MyAppDelegate class]));

当您设置状态栏隐藏状态时,您将收到您发送的自定义通知

于 2013-02-06T19:22:06.387 回答
1

根据 Or Arbel 的回答,我编写了这个类,它会发送通知以方便您使用。

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

于 2013-09-30T18:10:49.367 回答
0

您可能会frame改为观察应用程序的主窗口(或其子视图之一?),或覆盖某些视图的layoutSubviews方法。

于 2012-12-05T19:57:53.607 回答