【问题标题】:-[UIApplication setStatusBarHidden:withAnimation] does not fire KVO notifications for @"statusBarHidden" key-[UIApplication setStatusBarHidden:withAnimation] 不会为 @"statusBarHidden" 键触发 KVO 通知
【发布时间】:2012-11-23 17:40:26
【问题描述】:

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

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

[[UIApplication sharedApplication] setStatusBarHidden:YES]

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

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

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

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

【问题讨论】:

标签: ios uikit


【解决方案1】:

根据 Or Arbel 的回答,我编写了这个类,它会发送通知以供您参考。

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

【讨论】:

  • 请注意,这仅适用于显式调用 setStatusBarHidden 等。代码不会因为 UIViewController childViewControllerForStatusBarHidden 隐藏状态栏的机制而被触发。
  • @SeanLangley 没想到。感谢您的反馈!
【解决方案2】:

我找到了解决方案:

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

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

【讨论】:

    【解决方案3】:

    背景

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

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

        unsigned int statusBarHidden:1;
    

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

    解决方案?

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

    可能适合您的一件事是使用method swizzlingsetStatusBarHidden: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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 主窗口的框架没有改变。它仍然是全屏。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      相关资源
      最近更新 更多