views:

1437

answers:

2

I have an NSDate object created by

NSDate *date = [[NSDate alloc] init];

Later, I want to reset the date to the "now", so I thought that

[date init];

or

date = [date init];

might do the job, but they don't. Instead,

[date release];
date = [[NSDate alloc] init];

works. I'm a bit confused about this, since in the documentation for - (id) init, it says:

Returns an NSDate object initialized to the current date and time.

and since date is already allocated, shouldn't it just need an init message?

+6  A: 

Think of alloc and init as logically inseparable halves of a constructor. You can only call methods beginning with "init" once on a given object — once the object has been initialized, and it's an error to initialize it again. This is true for any Objective-C object, not just NSDate. However, NSDate objects are also immutable — once created, they can't change.

The reason the latter code works is because you're creating a new instance of NSDate, which is the correct thing to do. You can also use [NSDate date] to accomplish the same thing. Be aware that it returns an object that you don't (yet) own, so you'll need to retain it if you need to keep it around, and release it later.

Be aware that if you receive an object from someone, it has already been initialized. (If not, it's a programming error in the code that provided it, or is an extremely uncommon exception to the rule.)

Quinn Taylor
So which is more "idiomatic" to Objective-C? To use `[NSDate date]` and `retain`, or the above `[[NSDate alloc] init]` and `release`?
Jesse Beder
There's not one that's more idiomatic across the board, it just depends on what you want. However, not all classes have "convenience constructor" methods, but they will always have -init... methods. In any case, the convenience method handles the alloc/init for you and autoreleases the object. Some people are very adamant one way or the other about autorelease, but I find that reasonable use of autorelease is acceptable and often simplifies code. If you don't understand Objective-C memory management fully, that's the first thing I'd study up on.
Quinn Taylor
+3  A: 

If you want to get the current date you can just use:

NSDate * now = [NSDate date];

If you want to keep it then retain it.

NSDate * now = [[NSDate date] retain];

You can't reset NSDate with init, init is only for initializing the object for the first time.

You could just get another date:

NSDate * now = [[NSDate date] retain];
// use the now object
// need new date
[release now];
now = [[NSDate date] retain];
// once you don't need it release it
[now release];

The date message returns autoreleased instance of NSDate, hence the release or autorelease.

The autorelease is used for cases where you don't want to worry about where exactly you need to release the object - it is put into autorelease pool. Object in autorelease pool are released after the end of event loop iteration, or when you call release on pool ... (see more in Apple docs about memory management).

Btw. the [NSDate date] is a convenience method it's probably something like (not quaranteed to be exactly the same but functionally similar to):

- (NSDate *)date
{
    return [[[NSDate alloc] init] autorelease];
}
stefanB
+1 because I see you don't have the "Necromancer" badge yet. =P
Dave DeLong
I was just answering some other question and I noticed this question on top of the question list on the left so I jumped ... but thanks anyway
stefanB