静态 UIView 添加到 superview 后变为 nil

Static UIView becomes nil after added to superview

我有一个静态视图,用于在 UI 中显示为加载指示器。

static UIView *loadingView;

在我的 class Loading.m 中,我在 show() 被调用时将 loadingView 添加到我的容器中

+ (void)show {
    if (loadingView == nil) {
        UIWindow *containerView = UIApplication.sharedApplication.keyWindow;
        
        loadingView = [UIView alloc] init];
        [containerView addSubview:loadingView];
    }
}

当调用 dismiss() 时,我将其从 superview 中删除:

+ (void)dismiss {
    if (loadingView != nil) {
        [loadingView removeFromSuperview];
        loadingView = nil;
    }
}

我发现 loadingView 添加到 containerView 后将永远为零,所以我会继续添加更多 loadingView 到我的 containerView 并且它不会被删除当调用 dismiss() 时。当我打印 UIApplication.sharedApplication.keyWindow 时,它显示 UIView 已添加到堆栈中。在 show() 完成后,loadingView 似乎失去了对 containerView 的引用。

什么给了?

您是如何检测到“loadingView”为零的?

请通过代码或在调试器中使用“po”进行验证。

如果您刚刚在变量列表中看到“nil”值,有时是 Xcode 调试器错误。 当变量列表中的变量为“nil”,但它不是“nil”时。

的确,这个问题可能会产生更深层次的后果:

  • 您使用静态UIView。如果您的应用程序在 ARC 下,系统会自动决定对象在不可见时是否可以存活。因此,在对可见对象使用 static 声明之前应该三思。
  • 如果您的对象确实响应 removeFromSuperview 之类的消息并且 .superview 不是 nil - 这意味着该对象肯定不是 nil。如上所述,它是调试器的错误(发生在 运行 设备上的应用程序在 XCode 下)。

这个 post 的目标 - 注意 UIView 对象层次结构,其中父对象具有 .subviews 非空 NSArray 属性,表示所有对象, 添加为子视图。它们将由 ARC 自动释放,然后从堆栈中移除 VC。因此,在 static UIView * 声明的情况下,ARC 将保持加载其所有父元素,直到它被手动从 superview 中删除。换句话说,static UIView * 是一种潜在的危险构造,可能导致内存泄漏或其他冲突。例如,控制加载指示器的更好方法是检查当前顶部的最后一个子视图元素 VC:

if (self.view.subviews && [self.view.subviews.lastObject isKindOfClass: [loadview class]]) {
    [self.view.subviews.lastObject removeFromSuperview];
}

在这种情况下,您没有调用 nil 对象方法的风险(应用程序也会崩溃)和手动生命周期控制的麻烦。