I was digging into memory management, i found this.
I created a property button.
#property (nonatomic, retain) UIButton *button;
In ViewdidLoad method, i have written following code.
self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];
Doing XCode analyze, i am getting potential leak of an allocated variable on line 33 i.e; self.button.
Why does this happens? If i create a local UIButton and assign it to self.button and use it, then there is no potential leak. If i alloc memory to self.button or any property variables, it leaks.
Thanks
Jithen
Assigning a value to self.button calls the synthesized setter method:
- (void)setButton:(UIButton *)button;
Because you added the "retain" attribute to your property declaration, the synthesized setter will automatically call "retain" on the object that is set. This ups the retain count of the object.
Calling "alloc" on UIButton also ups the object's retain count.
So doing self.button = [UIButton alloc] essentially will up your retain count by 2. That's why there's a potential leak.
You can fix this by doing either:
self.button = [[[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)] autorelease];
or
UIButton *temp = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = temp;
[temp release];
or
_button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
#property (nonatomic, retain) UIButton *button; using this you are retaining object.
Now using self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)]; you are allocating memory and retain count is increased by 1.
So in you case this is a leak as retain count of object is increased. In case if you have local object and you alloc then again releasing it . So there is no extra retain count and there is no leak.
Abstarct
When you use factory method or create object using alloc,new,retain,copy,mutableCopy your object has +1 retain count every time. You own object in this case. You are responsible for releasing it. So you need to release object after you finish using object which cause -1 retain count to object.
EDIT
Now you are doing
#property (nonatomic, assign) UIButton *button;
self.button = [[UIButton alloc] init];
[self.button release];
Here you are accessing object using self which invokes on variable of your created property. You are sending +1 retain count over property object so it becomes 2 as property it self has getter and setters. So instead of doing this you can use instance variable like this.
#property (nonatomic, assign) UIButton *button;
_button = [[UIButton alloc] init];
[_button release];
Before ARC, you would normally do this for a retain variable:
UIButton* btn = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = btn; // property increases retain count because of its declaration as "retain"
[btn release];
with ARC, you would probably do this:
#property (nonatomic, weak) UIButton* button;
self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];
the second example illustrates that you don't really need to have your property retain the button (via retain or strong) because when you add a subview to a view container, the containing view will retain the new child.
Of course, there are some exceptions. Sometimes, you might actually want to remove your view (button) from the superview, but not let it be released, because you'll add it back later.
So, sometimes, it's valid to retain UI objects. Usually, it's not necessary, though.
Update: I would like to comment here that this kind of problem is why Apple wants people to use ARC. This is a really basic memory management scenario, that continues to foil lots and lots of new developers. At this point, there's very little reason for beginning iOS developers not to be using ARC.
Your UIButton instance is being retained twice. [UIButton alloc] creates a retained instance and the button property is retaining it when assigned via self.button. With MRC (Manual Reference Counting) code you need to release anything you retain.
When you create the button do the following:
UIButton *button = [[[UIButton alloc] initWithFrame:...] autorelease];
self.button = button;
Alternatively, use the preferred creator method for `UIButton':
self.button [UIButton buttonWithType:UIButtonTypeCustom];
self.button.frame = CGRectMake(...);
You also need to release the button wherever you clean up objects assigned to your properties. You're coding will be much simpler if you use ARC (Automatic Reference Counting) instead of MRC.
I don't know whether you have released it or not but whenever we alloc memory, we have to release it(if ARC is not used in your project).
So just release it in dealloc like this:
-(void)dealloc {
[button release];
[super dealloc];
}
Related
Why is blackview always null?
#property (strong, nonatomic) UIView *blackView;
[_blackView setFrame:self.view.bounds];
[_blackView setBackgroundColor:[UIColor colorWithWhite:0 alpha:0.8]];
[self.view addSubview:_blackView];
NSLog(#"%#", _blackView); // i get null
I was instantiating it using alloc init before but i need to access this view between methods so i am using it as a property
Try using self.blackview and initialize
self.blackview = [[UIView alloc] initWithFrame:self.view.frame];
Before you do anything to the object(UIView). You must allcate momery for it, and do some initializations. Use alloc and init method. Like:
UIView *blackView = [[UIView alloc] initWithFrame:CGrectMake( , , , )];
I must say, this is something that even the beginners should know.
After you have created a property. Make sure you have synthesized it.
#synthesize blackView;
And then make sure you alloc some memory to it atleast, use
self.blackView = [[UIView alloc]init];
And then you can perform, any function on it, that you want.
#property (strong, nonatomic) UIView *blackView;
Here you have made the decalaration. But that does not mean that you have allocated any memory to it.
In your implementation file you need to allocate memory to it and initialise it as well.
If you are using XCode version 6 and above you dont need to synthesize your property because that is done by Xcode itself.
Otherwise you need to syntesize your property.
#synthesize blackView;
self.blackView = [UIView alloc]initWithFrame:self.view.bounds];
Also if you have a nib file, and there you have alraedy added a UiView and you want it to be your blackView then you have to make an IBoutlet Connection from your nib file to your .h file. in this case you dont need to initialise or allocate memory to your UIView object. That is done by iOS SDk itself.
I have a question about memory management.
For example I have an iPhone application that uses multiply programmatically created views.
for example programmatically generated buttons.
UIButton *myButton=[UIButton alloc] initWithFrame:...; //etc
then, normally we add this button to subviews array:
[self.view addSubview:myButton];
then we releasing button.
[myButton release]
When I need to remove this button how can I keep track on this button in subviews array?
I know I can do this using tag property but I think exists another way to keep connection with it.
You can simply assign it to an instance variable:
UIButton *myButton = ...;
[self.view addSubView:myButton];
myInstanceVariable = myButton;
[myButton release];
You just need to be careful: as soon as you do something like [myInstanceVariable removeFromSuperview]; it might get deallocated immediately (if you haven't retained it) and it would then point to invalid memory.
You can try to declare somewhere a retain property of UIButton* type, that can be assigned with pointer value to your button instance:
#interface myclass
#property (retain, nonatomic) UIButton *savedButton;
#end
#implementation myclass
#synthesize savedButton;
- (void) someMethod...
{
...
UIButton *myButton=[UIButton alloc] initWithFrame:...;
[self.view addSubview:myButton];
self.savedButton = myButton;
[myButton release];
...
}
...
#end
I have two classes:
RootViewController.h
RootViewController.m
In my RootViewController.h
// in .h file
UITextField* myTextField_;
#property (nonatomic, retain) UITextField* myTextField.
In my RootViewController.m
// in .m file
#synthesize myTextField = myTextField_
// in dealloc
[myTextField_ release]
// in viewDidLoad
UITextField* tf = [[UITextField alloc] init] initWithFrame:CGRectMake(200,6,100,30)];
[nameTextField_ = tf];
[tf release]
My question is,
Does that create any memory leaks? Or will that crash? Are there better ways to create an instance of UITextField so I keep a reference to it? Perhaps
myTextField_ = [[UITextField alloc] init] initWithFrame:CGRectMake(200,6,100,30)];
would that be sufficient?
The simpliest way is to do this like this:
.h:
UITextField *myTextField;
#property (nonatomic, retain) UITextField *myTextField;
.m
#synthesize myTextField;
- (void)viewDidLoad {
myTextField = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)];
}
- (void)dealloc {
[myTextField release];
}
You will have one instance which is allocated and released in most clean way and you will have reference to this textfield all the time.
You should not do [tf release] as you are accessing your variable directly.
If you access it via self. notation that it will be called [tf retain] and then you should release tf. So in your current version all is ok besides line where you are releasing.
[nameTextField_ = tf];
change:
[self setMyTextField:tf]
Yes, this will do:
myTextField_ = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)];
You can also use this:
self.myTextField = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)] autorelease];
(when using the property it will retain, when using directly the member myTextField_ it won't (automatically) retain). Also alloc will set retainCount to 1 so it will eventually need to be released (in your case in dealloc method you can use either [myTextField_ release]; or self.myTextField=nil;);
Not sure what this is (I believe it will show up some compile errors):
[nameTextField_ = tf];
I declared a UIImage and a UIImage View in one viewcontroller like this:
In the .h file:
UIImageView* itemImageView;
UIImage* itemImage;
#property (nonatomic, retain) UIImage* itemImage;
#property (nonatomic, retain) UIImageView* itemImageView;
In the .m file:
#synthesize itemImage, itemImageView;
In another view, I set its value:
UIImage *image = [UIImage imageNamed:#"name1.png"];
imgView.itemImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 82, 166)];
imgView.itemImageView.image = image;
[self.parentViewController.view addSubview:imgView.itemImageView];
[self dismissModalViewControllerAnimated:YES];
Inside this method, the retain count of itemImageView is 2.
But when I go back to the view where I put the property and the synthesize, the retain count is 0 and I cannot access the object.
Any idea whats happening?
Your code here looks ok. (Aside from a memory leak) You're assigning an ImageView with a retain-count +1 to itemImageView, which will increase it to two. You need to call release on your ImageView after setting it to itemImageView:
UIImageView* iv = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 82, 166)];
imgView.itemImageView = iv;
[iv release];
However, this doesn't fix your problem (it will even make it worse..)
Can you show more code? Have you tried stepping through it with the Debugger?
UIImageView* itemImageView;
...
#property (nonatomic, retain) UIImageView* itemImageView;
...
imgView.itemImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 82, 166)];
This causes a double retain since alloc increases the retain counter by 1, and so does the retain setting of the #property.
The general pattern for setting properties is like so:
.h:
SomeClass* someClass;
...
#property (nonatomic, retain) SomeClass* someClass;
.m:
SomeClass* temporarySomeClass = [[SomeClass alloc] init];
self.someClass = temporarySomeClass;
[temporarySomeClass release];
...
Here, we're using a temporary variable to hold the object we alloced, and then doing a release right after.
You'll see that in the Apple example code for sure.
your problem is with this line:
[self.parentViewController.view addSubview:imgView.itemImageView];
this should most likely be edited as such:
[self.parentViewController.view addSubview:self.parentViewController.itemImageView];
this leads to the question of whether imgView is really equivalent to parentViewController.view. if you wanted it to be, then you need to figure out where that got assigned and see where you messed that up. if not, then theres no point in using it for anything but a temporary container to build ur objects in before assigning it.
edit: the memory leak is a separate issue yes, but im not sure how u declared imgView in the method so i left that for you to solve :)
Is this proper memory management? What I'm wondering is if I am supposed to release after the alloc in -viewDidLoad.
SomeViewController.h
#import <UIKit/UIKit.h>
#interface SomeViewController : UIViewController {
UIButton *someButton;
NSString *someString;
}
#property (nonatomic, retain) IBOutlet UIButton *someButton;
#property (nonatomic, copy) NSString *someString;
#end
SomeViewController.m
#import "SomeViewController.h"
#implementation SomeViewController
#synthesize someButton, someString;
- (void)viewDidLoad {
[super viewDidLoad];
someButton = [[UIButton alloc] init];
someString = [[NSString alloc] init];
}
- (void)viewDidUnload {
self.someButton = nil;
self.someString = nil;
}
- (void)dealloc {
[someButton release], self.someButton = nil;
[someString release], self.someString = nil;
[super dealloc];
}
#end
Thanks
Edit: one more thing. If I place a UIButton in IB, do I still need to alloc it?
It's quite a long story which you may find by googling around, and someone may enter here, but to keep it short, here's a few tweaks:
- (void)viewDidLoad {
[super viewDidLoad];
self.someButton = [[[UIButton alloc] init] autorelease];
self.someString = [[[NSString alloc] init] autorelease];
}
I.e. use the setters (self.something = ...;) and always either release or autorelease any alloc you do. (The logical distinction would be who "owns" the objects; with these tweaks the function gives up ownership and the class gets it.)
edit: no, if you create a button in IB, the button will just be there, allocated and initialized with your styles.
When you call init on an object, the retain count goes to 1. You have two different setter attributes: one is "retain" for your UIButton, and the other is "copy" for your NSString. When you call
self.someButton = someUIButtonObject;
someUIButtonObject gets a retain message and so its retain count goes up to 1. In the case of your original code, calling release in dealloc will release one reference to someUIButtonObject, but it will still have a retain count of 1 and will thus be leaked.
The other case with your NSString has a different problem but still leaks memory. Here your call to [[NSString alloc] init] results in a new string object, and then calling
self.someString = someNSStringObject;
results in the creation of a brand new object which copies the content of someNSStringObject. In this case, someNSStringObject and the setter's copied object each have a retain count of one. Here, you leak the string you alloc init-ed because you no longer have a reference to it and it goes out of scope with a retain count of one.
A quick side note: I don't know what your actual code looks like, but don't forget that NSStrings are immutable (so just calling [[NSString alloc] init] is pretty useless) and UIButton needs a frame (try [[UIButton alloc] initWithFrame:(CGRect)frame];).
Basically you need to match each call to retain, copy, or alloc with a call to release (or autorelease). It is appropriate so use
self.someButton = [[[UIButton alloc] init] autorelease];
Which will release the object, though at some unknown time in the future. Don't use autorelease if your memory is very tight and you need memory ASAP. In that case you would do:
UIButton* tempButton = [[UIButton alloc] init];
self.someButton = tempButton;
[tempButton release];
which guarantees that you don't have large objects waiting around in your autorelease pool.
Also, always use the getters/setters to access these properties (self.someButton as opposed to someButton). That way you don't accidentally assign someButton to a new pointer and leak the old one.
When you create a button in IB, the XIB holds a reference to the button (+1 retain count). If you create an IBOutlet so you can access the button programmatically, you get another retain on the object, so if you have an IBOutlet to someButton, someButton has a retain count of 2 as soon as the XIB is loaded. You do not need to alloc the object, that is done automatically when the XIB is loaded into memory. Also, you are only responsible for releasing one reference to the button (your IBOutlet reference). In general, it is a good practice to release your reference as soon as you know you no longer need it. For example, if you know you need a button and have to do initial customization and nothing else, then you would probably do something like this:
-(void)viewDidLoad {
// Do some customization of someButton
[someButton release];
}
Otherwise you would probably release someButton in viewDidUnload since you know at that point you won't need the reference to the button anymore.
If your button is set in IB, you do not need to allocate it in the code (IB does it for you).
Basically, each object you created using alloc or new, should have a release somewhere in your code. If it's an interface variable, you should release them in the dealloc function.