Chan Tak Zee
Chan Tak Zee

Reputation: 97

Static UIView becomes nil after added to superview

I have a static view that is used to display as a loading indicator in the UI.

static UIView *loadingView;

in my class Loading.m I add loadingView into my container when show() is called

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

and when dismiss() is called I remove it from superview:

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

I found loadingView will always be nil after being added into containerView, so I will keep adding more loadingView into my containerView and it will not be removed when dismiss() is called. When I print UIApplication.sharedApplication.keyWindow it shows an UIView has been added into the stack. It seems like loadingView has lost its reference into containerView after show() is completed.

What gives?

Upvotes: 0

Views: 488

Answers (2)

ETech
ETech

Reputation: 1607

Indeed, this question can have deeper consequences:

  • You use static UIView. If your application is under ARC, system automatically decides if objects can live when they are not visible. So, you should think twice before using static declaration for visible objects.
  • If your object does respond to messages like removeFromSuperview and .superview is not nil - it means that the object is not nil for sure. As said above, it is bug of debugger (happens when running the app on device under XCode).

The goal of this post - to pay attention to the UIView objects ierarchy, where parent object has .subviews non-null NSArray property, indicating all objects, added as subviews. They will be autoreleased by ARC next to removed from the stack VC. So, in case of static UIView * declaration, ARC will keep loaded all its parent elements until it will be manually removed from superview. In other words, static UIView * is potentially dangerous construction and can lead to memory leaks or other conflicts. Better way to control loading indicator, for instance - is to check last subview element of current top VC:

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

In this case you have no risk to of calling nil object methods (app crashes as well) and headache of manual lifecycle control.

Upvotes: 1

Dmytro Hrebeniuk
Dmytro Hrebeniuk

Reputation: 154

How you detected that's "loadingView" is nil?

Please verify it via code or using "po" in Debugger.

If you just saw "nil" value in variables list, sometimes it's Xcode debugger bug. When variable "nil" in variable list, but it's not "nil".

Upvotes: 0

Related Questions