I run the analyse build on Xcode, and get a warning for a leak because of an object that is a property and instance var
.h
UIView *_transparentView; }
#property (nonatomic, retain) UIView *transparentView;
.m
#synthesize transparentView = _transparentView;
self.transparentView = [[UIView alloc] initWithFrame:transparentViewFrame];
- (void)dealloc {
[_transparentView release];
so I release the ivar on dealloc, but how to release the property?, [self.transparentview release] ??
As Tom has answered replace the line that assigns the "transparentView" with:
self.transparentView = [[[UIView alloc] initWithFrame:transparentViewFrame] autorelease];
when you any value to a retained property you should you should release the assigned value if you are done with it, and release the property when deallocating the class.
Related
In ARC, I want to release the custom view added to parent view and array.
#property (nonatomic, weak) IBOutlet UIScrollView* panelScroll;
#property (nonatomic, retain) NSMutableArray *medsSectionViews;
Above are the two properties in which a customview object is added as below:
CustomView* newView;
newView = [[CustomView alloc] init];
[panelScroll addSubview:newView];
[self.medsSectionViews addObject:newView];
newView = nil;
Its not releasing the object. What is the problem? How can I achieve it? Please mention the reference count at required points.
CustomView *newView = [[CustomView alloc] init]; // 1 owner (the newView local variable)
[panelScroll addSubview:newView]; // 2 owners (local variable, the superview panelScroll)
[self.medsSectionViews addObject:newView]; // 3 owners (local variable, superview, array medsSectionViews)
newView = nil; // 2 owners (superview, array)
now
[array removeAllObjects]; // 1 owner (superview)
[newView removeFromSuperview]; // 0 owners
// view gets deallocated because it has no owners
Some method will retain object:
In your code:
1. addSubview:
2. addObject:
retain your view;
so your just need:
[array removeAllObjects];
[newView removeFromSuperview];
and why newView = nil can't release view ?
Because In ARC it's use Reference counting to management object life cycle.
Your newView variable appears to be a local variable. As soon as that goes out of scope it will release it's strong reference to your view. Thus you don't really have to set it to nil.
You have 2 other strong references:
Arrays maintain strong references to their contents.
When you add a view to a superview, the superview holds a strong reference.
If you want it released, you need to both remove it from the array and remove it from it's superview. Note that it will then be deallocated.
This question already has answers here:
Should IBOutlets be strong or weak under ARC?
(11 answers)
Closed 7 years ago.
When not using interface builder I always keep strong references to UI elements:
#interface myViewController : UIViewController
#property (nonatomic, strong) UILabel *folderLabel;
And then add them like this:
[self.view addSubview self.folderLabel];
where the initialiser is thus:
-(UILabel *)folderLabel{
if(!_folderLabel) {
_folderLabel = [[UILabel alloc] init];
_folderLabel.text = #"foo";
}
return _folderLabel
}
I have been told that this is bad for some reason and they should always be weak..
#property (nonatomic, weak) UILabel *folderLabel;
-(UILabel *)folderLabel{
if(!_folderLabel) {
UIlabel *folderLabel = [[UILabel alloc] init];
folderLabel.text = #"foo";
[self.view addSubview:folderLabel];
_folderLabel = folderLabel;
}
return _folderLabel
}
Is the strong reference a bad thing here?
When you add the subview to self.view, it gets retained. One pattern that works is to alloc the subview and store it in a local variable, add it to self.view then assign it to the ivar.
#interface Rectangle
#property (retain) UIView *view;
#end
#implementation Rectangle
CGRect frame = CGMakeRect();
self.view = [[UIView alloc] initWithFrame:frame]
Student *student=[[Student alloc]init];
[student release]; // not using this but using dealloc on it see below
(void) dealloc {
[_view release];
[super dealloc];
[student dealloc];
}#end
My question is:
here why we have to deallocate the memory on super object ???? what happen if we deallocate the memory on student with release it?????
retain and dealloc are not compliments. retain and release are complements, adding to and subtracting from an object's reference count respectively.
If your synthesized setter does a retain, then your dealloc should do a release (and a [super dealloc]).
The modern approach is to use ARC, drop the #synthesize, and always refer to your properties with the synthesized setters and getters, like this:
id foo = self.property;
self.property = foo;
Except in init, where it's better to say:
_property = foo;
I am working on the UIPopover and in one of the example I found that the Popover object is
created but then the object is assigned to the property of the Viewcontroller.
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:content];
self.popoverController = aPopover;
What is the merit in such assignment and any reason for not assigning object to the property directly?
There is no "merit" in it. Saying
self.popoverController =
[[UIPopoverController alloc] initWithContentViewController:content];
would be absolutely equivalent.
On the other hand there is nothing wrong with using a temporary variable (aPopover) as shown in your example. It's just a name (a pointer); there is no significant waste of space or time. Moreover, saying self.popoverController repeatedly (either to set or to get its value) is to be avoided, because this is a method call - you are passing through the setter method or getter method (which may be synthesized, may have side effects, and does in fact take some extra time). Thus, when there is much configuration to be done (for example), it is best to do it as shown in your example:
UIPopoverController* aPopover =
[[UIPopoverController alloc] initWithContentViewController:content];
// lots of configuration here, using the local automatic variable aPopover...
// ...and then, only when it is all done, call the setter:
self.popoverController = aPopover;
The only reason for that is that you probably read this in a tutorial somewhere. And the author did it for readability for beginners. You could absolutely use:
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:content];
All depending on how familiar you are with programming in general and how readable you want your code to be.
I agree with the others that, in this case, the assigning of the popover controller to a local variable before later assigning it to a class property is largely a stylistic matter. But this is only the case because you are keeping a strong reference to that popover controller. There are other situations where you have weak properties, in which this local variable pattern is critical.
For example, let's assume that we have a bunch of controls that we're going to add to our view controller's view programmatically:
#property (nonatomic, strong) UIView *containerView;
#property (nonatomic, strong) UILabel *usernameLabel;
#property (nonatomic, strong) UILabel *emailLabel;
// and more labels
When you want to add these to your view controller's view, you could do something like:
- (void)addSubviewsAtPoint:(CGPoint)location
{
self.containerView = [[UIView alloc] initWithFrame:[self frameForContainer:location]];
[self.view addSubview:self.containerView];
self.usernameLabel = [[UILabel alloc] initWithFrame:[self frameForUsernameLabel]];
[self.containerView addSubview:self.usernameLabel];
self.usernameLabel.text = self.username;
self.emailLabel = [[UILabel alloc] initWithFrame:[self frameForEmailLabel]];
[self.containerView addSubview:self.emailLabel];
self.emailLabel.text = self.email;
// etc.
}
But it also means that when you remove the subviews, you not only have to remove the container view from your view hierarchy, but you also have to remember to nil all of the properties for all of those subviews:
- (void)removeSubviews
{
[self.containerView removeFromSuperview];
self.containerView = nil;
self.emailLabel = nil;
self.usernameLabel = nil;
// etc.
}
This introduces a maintenance issue, that every time you add a new control via addSubviewsAtPoint, that you also have to remember to add it to removeSubviews, too, or else you might be hanging on to the control well after you've removed it from the screen.
To simplify your life, you might make all of these properties weak (with the intuition being that it's the view that owns these subviews, not the view controller):
#property (nonatomic, weak) UIView *containerView;
#property (nonatomic, weak) UILabel *usernameLabel;
#property (nonatomic, weak) UILabel *emailLabel;
// etc.
But now, using ARC, your addSubviewsAtPoint no longer works, because when you assign an object to a weak property, if there are no other strong references, it will be immediately become nil:
self.containerView = [[UIView alloc] initWithFrame:[self frameForContainer:location]];
[self.view addSubview:self.containerView]; // FAIL!!! self.containerView will be nil!
So, instead, we employ that local variable pattern of your question to ensure that the controls are not prematurely deallocated while we're adding them to our view:
- (void)addSubviewsAtPoint:(CGPoint)location
{
UIView *containerView = [[UIView alloc] initWithFrame:[self frameForContainer:location]];
[self.view addSubview:containerView];
self.containerView = containerView;
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:[self frameForUsernameLabel]];
[containerView addSubview:usernameLabel];
usernameLabel.text = self.username;
self.usernameLabel = usernameLabel;
UILabel *emailLabel = [[UILabel alloc] initWithFrame:[self frameForEmailLabel]];
[containerView addSubview:emailLabel];
emailLabel.text = self.email;
self.emailLabel = emailLabel;
// etc.
}
And, as a result, because we're using weak properties, our removal of those subviews is now much simpler, as we don't have to nil all of those properties when we remove the containerView from our view controller's view:
- (void)removeSubviews
{
[self.containerView removeFromSuperview];
// because all of those `containerView` subviews were `weak`,
// we don't have to manually `nil` them
}
In the UIViewController documentation about the searchDisplayController property 1 it says:
If you create your search display controller programmatically, this property is set automatically by the search display controller when it is initialized.
And when I create my UISearchDisplayController thusly:
[[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self] autorelease];
-[UIViewController searchDisplayController] is not nil. However, it is nilled out after the event loop finishes, which causes the search display controller not to show when I touch inside the search bar. Nothing crashes. This is very weird. If I omit the call to autorelease, everything works:
[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
However, leaks the UISearchDisplayController (I verified this with Instruments). Since the searchDisplayController property is marked as (nonatomic, retain, readonly) I expect that it would retain the UISearchDisplayController after it is set.
This stackoverflow article is related.
I've run into the same thing. I create all of my controllers/views programmatically. Everything was working fine until I converted my project to use ARC. Once I did the UISearchDisplayControllers were no longer retained and the searchDisplayController property in each UIViewController was nil after the run loop ended.
I don't have an answer why this is happening. The Apple docs suggest that the SDC should be retained by the view controller but this is clearly not happening.
My solution was to create a second property to retain the SDC and I nil it when I unload the view. If you are not using ARC you need to release mySearchDisplayController in viewDidUnload and dealloc. Otherwise this is good as is.
In MyViewController.h:
#property (nonatomic, strong) UISearchDisplayController * mySearchDisplayController;
In MyViewController.m:
#synthesize mySearchDisplayController = _mySearchDisplayController;
- (void)viewDidLoad
{
[super viewDidLoad];
// create searchBar
_mySearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
_mySearchDisplayController.delegate = self;
_mySearchDisplayController.searchResultsDataSource = self;
_mySearchDisplayController.searchResultsDelegate = self;
// other stuff
}
- (void)viewDidUnload
{
[super viewDidUnload];
_mySearchDisplayController = nil;
// other stuff
}
The solution above works just fine, but I also found that you can use
[self setValue:mySearchDisplayController forKey:#"searchDisplayController"]
in the context of a UIViewController subclass.