Reputation: 97
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
Reputation: 1607
Indeed, this question can have deeper consequences:
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.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
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