Objective-C memory management: when do you use `[variable release]` vs `variable = nil` to clean up memory? - ios

I've people who use [variable release] and some other times variable = nil to clean up memory?
When do you use each one? and what are the differences?

variable = nil; will not release memory. self.property = nil; will release memory if [self setProperty:nil]; would, for example a synthesized property with the retain attribute. Calling [variable release]; will always release one reference of an object.

Depends on what you mean by "clean up memory".
release is the only thing that frees dynamically allocated memory allocated by alloc. alloc should always be paired with a call to release or autorelease somewhere.
Setting a varible to nil does not necessarily free any memory (see drawnonward's answer), and can be a source of memory leaks.
When you see a variable set to nil, it's about preventing it from accidentally being used later after its memory has been freed (this can cause crashes). While you can always set a variable to nil after a call to release, it's somewhat a matter of style when it's actually necessary. For example, you don't often see variables set to nil in the dealloc method of a class, since by that point an object won't be able to accidentally misuse such a variable anymore, since it's being nuked.

If a property is set to retain, then these 3 are equivalent:
[self setProperty:nil];
self.property = nil;
[property release]; property = nil;
In each case, the object will be released, and then set to nil so that all access to the object from then on will not be allowed. "nilling" the instance variable is handy since it ensures you can only ever release the object once in this context because calling self.property = nil twice will do nothing the second time, but calling [property release] will release the object twice even though you likely only retain it once.
Most of the time I find it least bug prone to let retain properties do their thing and try to stay away from explicit retain and release calls most of the time.

Related

use __weak to local variable in ARC

When you write code like below in ARC
__weak NSMutableArray* array = [[NSMutableArray alloc] init];
The compiler will show you a warning or error and say "Assigning retained object to weak variable. object will be released after assignment".
But if you write like this:
__weak NSMutableArray* array = [NSMutableArray array];
There is no error.
I'm wondering if the second usage is reasonable in some situations? What's the difference between these two codes from memory management perspective? How does it work?
There can be very subtle differences that the compiler cannot know.
Let's take an immutable version: [NSArray array] could return the very same static object every time. So your weak variable will point to a valid object, that has a strong reference somewhere else. Or think of the singleton pattern. On the other hand, when calling alloc/init, convention dictates that you're the only owner of that object, and that will typically leave you with nothing.
Also, the factory method certainly looks more like a (functional) method. In any case, it doesn't communicate ownership of what it returns very well. For an autoreleased object, it's not clear whether you're the the only owner or a shared owner.
They are the same because you lose the object instantly. Compiler cannot know probably, except alloc init, that the object will be lost.
In the first form, the method returns a retained object. ARC ensures, that the object is released when there is no strong reference on the call-site. This is immediately true, with the weak reference - thus, the compiler emits a warning or error.
In the second form, the method returns an unretained object. In this case, the compiler must ensure that the object is still valid across the return boundary. When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, then leaves all local scopes, and then balances out the retain while ensuring that the value lives across the call boundary. That is, there is a strong reference created by the compiler. This strong reference will be automatically released by the compiler generated code.
Thus, in this case there's no error or warning.
In the worst case, holding that object may require to use an autorelease pool. However the compiler can apply certain optimisations which avoids this. Thus we should not assume that the returned object lives in an auto release pool.
See specification: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#id14
See also this question on SO: Difference between [NSMutableArray array] vs [[NSMutableArray alloc] init]

Mark an object un-AutoRelease in ARC

As we all know, object will not dealloc immediately in ARC when no variable refer it. eg,
NSObject* obj = [[NSObject alloc] init];
obj = nil;
obj will dealloc after a time.(auto release pool drain).
Now, I want the obj dealloc right after it's been set to nil, which means the obj is not in auto-release-pool. But all other obj should work well as before, which means the program is still in ARC mode.
Is there a way, maybe macro or compiler flag, to do this?
First of all: You should not care about early deallocation. This is a strong code smell.
Second: Are you really, really sure, because -init does not put an object into ARP. Maybe the expression causes a retain autorelease combination, but compiling in release mode should optimize that away.
However, if it is in ARP you can close the ARP as mentioned by Hermann Klecker or – I think this is better – find the reason for being that object in ARP. There is no need for that.
Amin is right: the object is not in an autorelease pool. alloc, which created the object, does not engage a pool. On the other hand, you're right: ARC may not release the object immediately.
There is indeed an annotation you can use to force the release: objc_precise_lifetime. Adding that to the variable declaration will cause ARC to send release as soon as the object is no longer valid in the current scope.
However, Amin is also right that this is not very likely to be what you want. ARC knows what it's doing -- there are optimizations it can't make when you use this annotation -- and unless you know what it's doing too, you should strongly consider just letting it do its job.

Release NSMutableDictionary memory under ARC in iOS

In my app, I used the NSMutableDictionary and when I go to a specific view controller, the memory utilized increases more.
How can I free the used memory in Objective-C?
All you need to do is assign it to nil. Under ARC that's all that's needed to 'release' an object:
self.myMutableDictionary = nil; //It no longer exists.
Note that this kills the reference that the view controller this code is run from has - if this is the only strong reference, then the object will be removed and the memory freed. If another object(s) have strong reference(s) pointing to the dictionary, though, then the memory won't be freed until those references are also set to nil. It's the responsibility of the allocating objects to be responsible and set their references to nil when they no longer need the object.

How long does an autoreleased static object declared globally, survive in memory?

If I declare a static object handle in a class file in global scope. And the object assigned to this handle is an autoreleased one. Then for how long will this object remain in memory during my application life cycle ?
If I declare a static object handle in a class file in global scope. And the object assigned to this handle is an autoreleased one. Then for how long will this object remain in memory during my application life cycle?
Short Answer: You want your global to be a strong reference. In MRC, you must add the retains and releases for globals. In ARC, the global is implicitly strong (and ARC adds them for you).
Long Answer:
Under ARC, your static global variable is a strong reference. In MRC, you would retain such a variable when set and then release the previous object. If you did not, then you could still access it after it were deallocated (dangling pointer).
Because it is a strong reference, your object will remain valid until a) the strong reference by the global variable is given up and b) the autorelease pool is drained c) and of course any other strong references are given up.
So if you are using strong references for that global and you never reassign it (logically, giving up the global's strong reference), then your object would never be dealloc'ed.
When you use unsafe nonretained semantics (by decoration in ARC, or the default for a static in MRC), the object would be -dealloced when the current autorelease pool is drained and all strong references are removed. This is easiest to illustrate with a program (MRC);
static MONObject * GlobalObject;
//
// In MRC, you must add the reference counting to ensure you do not end up with a dangling
// pointer, so false is what how your program should be written in MRC.
//
// In ARC, your program will look like NonRetainedOwnership because it treats the global
// as a strong reference.
static const bool NonRetainedOwnership = ...T/F...;
...
// assume GlobalObject is accessed from one thread only -- i won't bother with
// the supporting code to illustrate how this should be made thread safe.
- (MONObject *)sharedObject
{
if (nil == GlobalObject) {
if (NonRetainedOwnership) {
// don't do this! lifetime will be determined by strong client references
// and the reference you rely on now will be lost when the thread's current
// autorelease pool is drained -- leaving you with a dangling pointer which
// will cause issues when -sharedObject is called again.
GlobalObject = [[MONObject new] autorelease];
}
else {
// Good - keep a strong reference:
GlobalObject = [MONObject new];
}
}
return GlobalObject;
}
- (void)disposeSharedObject
{
if (NonRetainedOwnership) {
GlobalObject = nil;
}
else {
// remove our reference, which was established at [MONObject new]
// assuming there are no strong external references, the object
// will be dealloc'ed -- but you should not make that assumption
// if you return it.
[GlobalObject release], GlobalObject = nil;
}
}
So if NonRetainedOwnership is true and you use MRC, then your object would typically be -dealloc-ed shortly after -sharedObject returns (assuming whoever called -sharedObject holds no strong reference). In this case, 'shortly' means the pool will often be drained a few frames back in your current callstack, often in AppKit or UIKit when you are on the main thread since I don't see many people explicitly create autorelease pools on the main thread. borrrden said after "1/60th of a second", and the assumption there is that the object is created and autoreleased in the main thread's run loop (correct me if I am wrong). The 'Kits create autorelease pools at each iteration of the main run loop, but your program could be running on a secondary thread or there could be an inner autorelease pool, so the lifetime has the possibility to be shorter or longer. Normally, you don't need to think about these things in much depth -- just use a strong reference here since you really have no other way to ensure the right thing happens with this global variable.
If you simply wrote: #autoreleasepool{[[MONObject new] autorelease];} NSLog("Hi"); then the object would (under normal circumstances) be released by the time NSLog were called.
The declaration of variable doesn't matter as such, The thing what matters is when did you assigned an autoreleased object to it, If it is assigned under any autorelease pool than it would drain it else it would be released on program termination by autorelease pool in main method!
The Variable is just a pointer and does not retain the object unless done explicitly, thats why retaining static objects is preferred: Why retain a static variable?
When the pool is 'drained'. This may not happen right away.
Please see a similar question
It depends. If the variable is initialized only once, and should stay around for the lifetime of the application, then no, it shouldn't be released (its memory will essentially be freed when the application exits, anyway). If, however, the value of the static variable changes, then yes, the previous object should be released when the static variable is set to a new object.

Ambiguous scenario for iPhone memory management

I have some difficulties to understand this scenario.
I create an object
I set its retained property to something
I forget to release its property
I release the object
As I didn't release the property in the dealloc method, will the scenario result in a memory leak or will the property be released automatically?
The way Cocoa works is that memory management always looks locally balanced, within any one method*. This is kind of the point. You should be able to tell whether you have a leak or error in a method just by looking at that one method. No global program knowledge required.
It is your responsibility to release an object if you received the object from a -copy, -alloc, -retain, or -new method.
If you do this:
[obj setProp:foo];
is it your responsibility to release foo? No - see rules. If obj retains it (and you're saying you happen to know that it does), then it is the responsibility of obj to release it, in its dealloc method if not sooner.
So if you did this, it's balanced, no matter what kind of property -prop is.
id obj = [[MyObject alloc] init];
[obj setProp:foo];
[obj release];
*except for within the implementations of init, copy, dealloc, and accessor methods.
Yes, it's leak.
Retain, alloc will increase the counter by one.
Release will decrease the counter.
It will free the memory when the counter reaches zero.
Think of setter as this:
[newvalue retain];
[property release];
property = newvalue;
So..
create an object => 0+1=1
assign it to some object as a retain property => 1+1=2
release the object => 2-1=1
You will have to release that object again sometime.
And, trust me autorelease doesn't work quite well in the iphone environment.

Resources