Inside an initialization method, I have the following code
- (id)init {
self = [super init];
if (self) {
UIButton *tempButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
tempButton.frame = CGRectMake(0,0,300,44);
// some custom code...
self.myButton = tempButton;
}
return self;
}
Where myButton is a retained property.
I know that, for what concerns memory management rules, this method equals this other:
- (id)init {
self = [super init];
if (self) {
UIButton *tempButton = [[UIButton alloc] initWithFrame:CGRectMake(0,0,300,44)];
// some custom code...
self.myButton = tempButton;
[tempButton release];
}
return self;
}
But in this case I need to use the first "version" because the buttonType property is readonly and I cannot change it after having the button initalized.
Since I find myself using the "non init-release" version in multiple methods all over my application, and for several object (most of them are NSString), my question is: not counting in this case the assignment to the property which retains the object, when the tempButton object will be released? Maybe at the end of the method/if statement? Or will the first "version" lead to an increased memory usage, since the object is not being released right away but after a certain amount of time?
I think you're a bit confused here: in both of your snippets, you create a tempButton object, but then you're assigning it to self.myButton. At that point, both tempButton and self.myButton are pointers to the same object. Now, presumably the myButton #property you're using is a strong property, so by assigning tempButton to it, you increase its retain count, and therefore in either version of the code it would have a retain count of +1 at the end, and would not be dealloc'ed.
If, hypothetically, myButton wasn't a strong property, then there would be an error in your code, and in both cases tempButton would be prematurely released and dealloc'ed. Here's what would happen in the two cases:
In your first version, since you're getting tempButton comes from something other than an init or copy method, it gets a retain count of +1, but is autoreleased. At the end of the current iteration of the run loop, the autorelease would kick in, bringing its retain count to 0 and causing it to be dealloc'ed.
In the second version, you first get a tempButton with a retain count of 1 because it's coming from an init method. But later on you explicitly release it, bringing its retain count to 0, at which point it is immediately dealloc'ed.
the non-init method is exactly the same as:
UIButton *tempButton = [[[UIButton alloc] initWithFrame:CGRectMake(0,0,300,44)] autorelease];
so the idea is to understand more about how the auto release pool works, its very useful most of the time but u need to understand how it works incase u will use the object later on in the app.
and to note something, when u add the temp button to ur view that view will retain it, and will release it when its removed from it, u can use instruments and check the retain count of the object if u wish to view how release/retain is going on if u want to see it in action.
Related
My IOS program is not ARC, code like this:
in the .h file i define five variables:
{
UILabel *label1,*lable2;
UIView *dwView;
NSMutableArray *wordsArray;
}
the code in the .m file like this:
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
viewArray=[[NSMutableArray alloc]init];
}
-(void)QuestionA{
dwView=[[UIView alloc] initWithFrame:CGRectMake(20, 50, 975.0, 620)];
label1 = [[UILabel alloc]initWithFrame:CGRectMake(10.0, 160.0, 950.0, 170.0)];
label2 = [[UILabel alloc]initWithFrame:CGRectMake(30.0, 160.0, 950.0, 170.0)];
[dwView addSubview:label1];
[dwView addSubview:label2];
[self.view addSubview:dwView];
[viewArray addObject:dwView];
[lable1 release];
[lable2 release];
[dwView release];
}
before I turn to another activity I log out the retain count of those variables:
{
[lable1 retainCount] ---> 2
[lable2 retainCount] ---> 2
[dwView retainCount] ---> 3
}
So: I wonder why it like this, and how can I release the retain count
to 0?
Presumably these are the retain counts before you call "release" at the end of your routine.
Calling the traditional "alloc" / "init" starts the newly instantiated object off with a retain count of 1. When you add dwView as a subview to a parent view, that increments the retain count. When you add dwView to the array, that also increments the retain count. Hence 3 there.
Same for the labels, you've added them as subviews, so that increments the retain count by 1 for each (giving you a retain count of 2).
The object will be released when the retain count hits zero (e.g. for your "dwView", that'll be when "self.view" is dealloc'd and when the "viewArray`" gets released).
If use ARC , you may try #autorelease{}
Every time, addview will make a copy of the view.
it has been mentioned many times in apple docs that never go by retain count.
if you are allocating for some memory make sure you call release on that.
its left to system to release that memory chunk and system will do that when retain count reaches zero
below is what apple docs says
Important: There should be no reason to explicitly ask an object what its retain count is (see retainCount). The result is often misleading, as you may be unaware of what framework objects have retained an object in which you are interested. In debugging memory management issues, you should be concerned only with ensuring that your code adheres to the ownership rules.
I am getting used to using weak and strong references and when to use them and when not and I got to a case like described below (check the comment about the warning)
#interface MPIViewController ()
#property (weak, nonatomic) UIView *subview;
#property (weak, nonatomic) UILabel *label;
#end
#implementation MPIViewController
// ...
// some code here
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
self.subview = [[UIView alloc] init]; // warning here: assigning retained object to weak property
self.label = [[UILabel alloc] init]; // no warnings
[self.view addSubView: self.subview];
[self.view addSubView: self.label];
}
// ...
// some code here
// ...
#end
From description of - (void)addSubview:(UIView *)view:
This method establishes a strong reference to view and sets its next
responder to the receiver, which is its new superview.
This means that this object won't be deallocated after method finishes as it's superview will retain it and hold a strong reference to it and therefore this view will be kept in memory for as long as its superview is there. Am I right here?
I am not sure also if I understand assigning here correctly. Warning says that it will be deallocated straight after the assignment but this sounds wrong as then it wouldn't be possible to assign any variable to a weak pointer as it would get deallocated in the next line of code?
For UILabel same assign works fine, however for UIView it doesn't? Does the compiler treat UIView somehow differently? This really puzzles me how that is even possible.
This code can be fixed easily just by assigning the UIView to a local method variable and then passing it to the setter like this:
UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;
Variables declared in the method are by default strong so having such a construction removes the warning as the compiler thinks that this variable has a strong reference so weak reference that is then assigned to will be kept as long as the method variable will point to it. BUT! how does that make sense as the tmpView is only a local method variable and will be dumped after method will finish?
To the first question:
Let's have a closer look to it:
self.subview = [[UIView alloc] init];
[UIView alloc] returns an instance with ownership +1. This is assigned to a (non-visible) strong reference, which build the self of -init. -init passes the ownership through. (This is not correct, if -init returns an instance which is not the original receiver, but for your case it is enough details.) So we can think of the return value of -init as an ownership transfer, too.
You assign this instance to a weak variable. In this moment it can be released. (Read: ARC does not promise to do it immediately, IIRC.) the instance variable can be nil before the object is hold by its superview. So this code is dangerous:
self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil
I do not believe that this is your problem, but it can be a problem. – Thinking again about it, it is your problem. Read the edit at the end. –To get rid of it, simply use a strong local variable:
UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;
The second question:
I do not know, why the compiler gives you no warning in the second case. What does happen, if you repair the first case?
At runtime a different handling of both cases is possible, because it is undefined, when the first instance is released. Maybe as a part of optimization a pointer is reused. More detailed:
__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];
The first instance would be dealloc'ed, when the second instance is created, because it overwrites the internal strong reference.
Again: Repair the first case and tell us, what happens with the second one.
An object need at least one strong pointer to it in order to be kept in memory.
So when you alloc it to a weak pointer that condition is not being met. Make your properties strong if you really need to access these views.
Until yesterday I thought I understood how properties memory management works, but then I ran an "Analize" task with XCode and got plenty of "This object is not own here". Here is a simple example that describes my problem :
MyObservingObject.h:
#interface MyObservingObject : NSObject
#property(nonatomic, retain) NSMutableDictionary *observedDictionary;
-(id)initWithDictCapacity:(int)capacity;
#end
MyObservingObject.m:
#synthesize observedDictionary;
-(id)initWithDictCapacity:(int)capacity {
self = [super init];
if (self) {
self.observedDictionary = [[[NSMutableDictionary alloc] initWithCapacity:capacity] autorelease];
}
return self;
}
- (void)dealloc {
// The following line makes the Analize action say :
// "Incorrect decrement of the reference count of an object that is not owned at this point by the caller"
[self.observedDictionary release], self.observedDictionary=nil;
[super dealloc];
}
What I don't understand is Why should I leave this property without calling release on it? My #property is set as retain (copy does the same), so when I'm doing self.myRetainProperty = X, then X got its retain count increased (it's owned by self), didn't it ?
You should let the setter do the releasing for you, so remove the call to release in dealloc:
- (void)dealloc {
self.observedDictionary=nil;
[super dealloc];
}
This is because the setter will be synthensized to something like:
- (void)setObject:(id)object
{
[object retain];
[_object release];
_object = object;
}
Which will work as desired when you pass in nil.
It did get increased, but when you set it to nil, the setter method first releases the backing instance variable, and only then does it retain and assign the new value. Thus setting the property to nil is enough, setting the ivar to nil leaks memory, though.
For your better understanding: the typical implementation of an autogenerated retaining setter is equivalent to something like
- (void)setFoo:(id)foo
{
if (_foo != foo) {
[_foo release];
_foo = [foo retain];
}
}
Also note that, as a consequence, you should never release properties like this. If you do so, the backing ivar may be deallocated, and messaging it (release by the accessor when setting the property to nil afterwards) can crash.
You don't need to do
[self.observedDictionary release]
before
self.observedDictionary=nil;
This is enough, because this is a property, and it will automatically send release to previous value
self.observedDictionary=nil;
The reason for the compiler warning is because of the way you are retrieving the object.
By calling
[self.observedDictionary release];
you are in fact going through the accessor method defined as
- (NSDictionary *)observedDictionary;
This returns your object but due to the naming of observedDictionary the compiler assumes that there is no transfer of ownership e.g. the callee will not have to release this object unless they take a further retain. It is because of this that the compiler thinks you are going to do an overrelease by releasing an object that you don't actually own.
More specifically the convention for method names that transfer ownership is for them to start with copy, mutableCopy, alloc or new.
Some examples
Here I have used a name that does not imply transfer for ownership so I get a warning
- (id)object;
{
return [[NSObject alloc] init];
}
//=> Object leaked: allocated object is returned from a method whose name ('object') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa
Fix 1: (don't transfer ownership)
- (id)object;
{
return [[[NSObject alloc] init] autorelease];
}
Fix 2: (make the name more appropriate)
- (id)newObject;
{
return [[NSObject alloc] init];
}
With this knowledge we can of naming convention we can see that the below is wrong because we do not own the returned object
[self.object release]; //=> Produced warnings
And to show a final example - releasing an object that implies ownership transfer with it's name
[self.newObject release]; //=> No Warning
Why would I use (inside my dealloc method)?
[myInstance release] instead of [self.myInstance release]
myInstance = nil instead of self.myInstance = nil
Although we use self.myInstance = [[[AClass alloc] init] autorelease] instead of myInstance = [[[AClass alloc] init] autorelease]?
Those practices are from numerous examples I see on the web.
1) [myInstance release] instead of [self.myInstance release]
prefer the former.
the returned value of self.myInstance is defined by implementation when a subclass has overridden the method myInstance. you're not interested in the behaviour of the interface of a constructed object during dealloc (since a subclass may override and return something other than your ivar).
what you are interested in dealloc is releasing the references you own before your object is destroyed. if the subclass has overridden myInstance, then it could:
a) return an ivar (declared in the subclass) that's already been released
or
b) the implementation of the override may return a newly created autoreleased object
either a or b could lead to an over-release and a crash (assuming everything else is correctly retained/released). this also suggests why you should assign nil to the ivar after releasing it.
this is also a classic example of how to trigger object resurrection. object resurrection occurs when an implementation of the getter/setter you call recreates its state after it's already been deallocated. the least offensive side-effect would cause a harmless leak.
2) myInstance = nil instead of self.myInstance = nil
again, prefer the former.
a formal response would look much like the response to #1 -- the rationale, side-effects and dangers apply here as well.
the safest way to handle this is to access the ivar directly:
[myInstance release], myInstance = nil;
because there may be really nasty side-effects (crashes, leaks, resurrection) which may be difficult to reproduce.
these dangers may be easily avoided and your code will be far easier to maintain. on the other hand, if people encounter the side-effects when using your programs, they will probably avoid (re)using it wherever they can.
good luck
Calling self.myInstance = uses the auto generated setter method. Calling [self.myInstance release]; calls release on the object returned by your getter method. It all depends on how your properties were set up (retain, assign?). There is no necessarily right or wrong answer to your question, since it all depends on the property in question. I suggest you read up on Objective C properties to get a better feel for this kind of thing.
And, unless myInstance was declared with assign, you wouldn't want to call self.myInstance = [[AClass alloc] init] You'd be much better off with self.myInstance = [[[AClass alloc] init] autorelease]
Note that using
myInstance = nil
instead of
self.myInstance = nil
Is incorrect (in the context of say a viewDidUnload method in a UIViewController subclass) if myInstance is a retain property, since if myInstance points to an object, it will be leaked!
This depends on a property that you defined in interface. For example if you define retain property:
#property (nonatomic, retain) NSObject *property;
then you may use just self.property = nil; in dealloc method, because it equals to:
[property release]; // releases previous property
property = [nil retain]; // [nil retain] returns just nil
The very same thing with self.property = [[A alloc] init];. This equals to
[property release]; // releases previous property
property = [[[A alloc] init] retain];
in case of property = [[A alloc] init]; property won't be retained.
Here's a full properties guide form Apple.
Actually using
self.myInstance = [[AClass alloc] init];
will lead in a memory leak, cause self.myInstance is using setter methods which leads in retain +1 along with alloc/init retain +1. So you'll get a retain count +2;
... = self.myInstance
and
self.myInstance = ...
are actually subroutine or method calls to getters and setters, which depending on how you define these subroutines, or have Objective C Properties create them, could do almost anything.
If the case of retain properties, the subroutines might play with the retain counts. If you do your own getters and setters, you could have them control the lights in your house, turning them on for none zero sets and turning the lights out when setting something to zero or nil. There doesn't even need to be a backing variable named "instance" which could be set by:
instance = ...
Memory management with delegates, it is my understanding that I don't retain delegates, I am a little unsure about what to do with the delegate if the view gets unloaded (via viewDidUnload) and later recreated (via viewDidLoad)?
#property(assign) SomeClass *someDelegate;
.
- (void)viewDidLoad {
[super viewDidLoad];
someDelegate = [[SomeClass alloc] init];
[someDelegate setDelegate:self];
}
-(void)viewDidUnload {
[super viewDidUnload];
[self setSomeDelegate:nil];
}
-(void)dealloc {
[super dealloc];
}
PS: I might be on the wrong track, I am just trying to get my head round this ...
cheers Gary
If you use assign for your property, you're not calling retain on the object.
This means that you should definitely NOT call release or autorelease on it!
Your line in your dealloc
[someDelegate release];
will cause a crash at some point down in the future - you should remove it. You don't need to care about assigned properties in the dealloc method.
Your line
[self setSomeDelegate:nil];
will not leak.
However, you seem to have [[someDelegate alloc] init] in your viewDidLoad method. This is unusual; it's normal for the delegate to be an external object, not one made by yourself. In your case, it's not really a delegate, it's just an object that does something for you - you should rename it and change the property to a retain (and remember to release it in dealloc).
Currently, if your property is set to (assign) and someone else sets it, you will leak your initial delegate. If you only use the delegate inside this class, perhaps it shouldn't be a property at all? If you just want to be able to read it from outside your class you might be able to use (readonly) instead of assign (and change [self setSomeDelegate:nil] to someDelegate=nil;)
Your line in viewDidUnload that sets the delegate to nil removes the issue you raise in your second comment - you're removing the delegate so by the time you get to viewDidLoad again, your delegate is already nil :)
This may shed some light to understand why
The reason that you avoid retaining delegates is that you need to
avoid a retain cycle:
A creates B A sets itself as B's delegate … A is released by its owner
If B had retained A, A wouldn't be released, as B owns A, thus A's
dealloc would never get called, causing both A and B to leak.
You shouldn't worry about A going away because it owns B and thus gets
rid of it in dealloc.