NSDate - How does the default initializer allocate space on the heap? - objective-c

I know it's good practice to explicitly alloc and init objects, but I'm confused why it is not needed for instances of NSDate in the following example:
NSDate *now = [NSDate date];
Appears to be the same as this...
NSDate *now = [[NSDate alloc] init];
I assume the date class method allocates space on the heap, but I have only found NSDate.h and not how Apple actually implemented the method.
Apple documentation simply says, "This method uses the default initializer method for the class, init."

+[NSDate date] is a "convenience constructor". Typically the implementation will look very similar to return [[[self alloc] init] autorelease].

Related

potential leak value stored never read in NSMutableArray

NOTE: i want to alloc my NSMutableArray and then assign data in it.
i got leak in below code
NSMutableArray *responseArr=[[NSMutableArray alloc]init];
responseArr =[response valueForKey:#"result"];
Also in here value stored never read
NSString *name=_txt_name.text;
if ([name length]==0) {
name=#"";
}
Also leak in below
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss"];
//below here i get leak
NSDate *dateStart = [[NSDate alloc] init];
dateStart = [dateFormatter dateFromString:startDate];
EDIT :
I have disable ARC using -fno-objc-arc in reachability Class even i get below leaks
This line
NSMutableArray *responseArr=[[NSMutableArray alloc]init];
Allocates a new NSMutableArray and assigns a reference to it to responseArr
This line
responseArr = [response valueForKey:#"result"];
Takes a value from a dictionary (that presumably is a reference to an NSMutableArray) and assigns that to responseArr. At this point there are no more references to the original NSMutableArray that you allocated, so it will be deallocated.
You can just say:
NSMutableArray *responseArr = (NSMutableArray *)response[#"result"];
Similarly with your date code, you could just say:
NSDate *dateStart = [dateFormatter dateFromString:startDate];
There is no need to assign an initial value, only to throw it away.
None of the code you have shown will cause leaks, assuming you are using ARC.
If you aren't using ARC, then start using ARC!
A. First snippet
Using MRC (MRR) you have to balance allocations with +alloc your own:
NSMutableArray *responseArr = [[NSMutableArray alloc]init];
responseArr = [response valueForKey:#"result"];
In the first line you allocate an instance of NSArray. You have to (auto-)release it later, otherwise it is a memory leak. I think you misunderstood that you create a new instance of NSArray using -valueForKey and assign the value of this new reference to responseArr. (Therefore you do not need a mutable array.) After that you created two objects having only one reference to the new one, you can never release the old one.
Do something like this:
NSArray *responseArr = [[NSArray alloc]init];
NSArray *resultArr =[response valueForKey:#"result"];
[responseArr release];
You do not have to do that with the object referred by resultArr, because it isn't created with +alloc-init. Here you get an introduction to ownership.
B. Third snippet
It is the same with the last example:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
You +alloc-init that instance object, but there is no release in your code. Therefore it cannot be released anymore, when the reference dateFormatter loses its extent (lifetime), i. e. returning from the method.
Add this code at the end of the method:
[dateFormatter release];
C. Second snippet
The second example has a different problem: You assign a value to the var name without using the variable in the code below. So assigning the value is meaningless.

initialize an instance in objective-C with alloc and init

I am learning Objective-C and I've just read about alloc and int methods. Before this point,when I wanted to create an instance of NSDate for example, I coded:
NSDate *now = [NSDate date];
Now I saw that the above can be written like this
NSDate *now = [[NSDate alloc] init];
Are the above do the same thing? As i have understood (hopefully correct) the first one creates and instance of NSDate, by sending the message date to the class NSDate. The second one, it just allocates space for the instance and initialize it, so that it is ready to work.
You would think the two things you list were definitely not the same thing based on a background knowledge of Objective-C, if you weren't familiar with NSDate. But in fact, they are the same thing in this case.
[NSDate date] is calling an NSDate class method that returns an NSDate object set to the current date and time.
Normally, a method call like [[NSDate alloc] init] would instantiate a new default object of the type requested, so you might expect that this would not be set to any date/time. However, the default NSDate object is in fact initialised with the current date and time, as discussed in the documentation, so in this particular case—they are the same thing.
As an aside, as with most NSObjects, you can also just call [NSDate new] to get the same effect as [[NSDate alloc] init] (and thus the same effect in this case as [NSDate date]).

alloc + init memory usage mechanism

I am just curious to know when an object has made by alloc, and a piece of memory allocated to it, why init don't use that piece of memory and changes the address of object?
NSDate *t = nil;
NSLog(#"t = %p",t); // t = 0x0
t = [NSDate alloc];
NSLog(#"t = %p",t); // t = 0x100107af0
t = [t init];
NSLog(#"t = %p",t); // t = 0x1001035a0
Two-step initialization allows us to do these kinds of things (namely, substituting an instance of a class for another depending on the initializer called). Class clusters all over Foundation and UIKit take advantage of this to return instances optimized for a particular use-case. For example, UIColor itself is just an interface for its subclasses that implement color caching (all the named initializers like +blackColor), the RGB color space (+colorWithRed:green:blue:alpha), the black and white color space (+colorWithWhite:alpha:), CIColor compatibility, etc. And so NSDate is too. When you call -init, Apple has means and motive to return a different object that implements the same interface as NSDate as an optimization because you honestly shouldn't care what you get as long as it doesn't launch the missiles when you try to message it properly.
As of the latest iOS SDK, calling [NSDate alloc] always returns the same memory location. You can verify this behavior with the following code:
NSDate *date1, *date2;
date1 = [NSDate alloc];
NSLog(#"date1: %p", date1);
date1 = [date1 init];
NSLog(#"date1: %p", date1);
date2 = [NSDate alloc];
NSLog(#"date2: %p", date2);
date2 = [date2 init];
NSLog(#"date2: %p", date2);
I suspect that it has to do with the fact that NSDate is a class cluster.
If the private subclasses of a class cluster have different storage requirements, it's impossible to know inside of alloc how much memory to allocate. One approach to solving this problem, and it appears this is the approach that Apple is using with NSDate, is to let the init and factory methods handle all the memory allocation, since those methods know what private subclass is actually going to be used.
At that point, all alloc is doing for you is allowing the user to preserve the [[NSDate alloc] init] pattern that's used for object creation everywhere in Objective-C. Since the memory location returned by alloc is always discarded, alloc may as well just return a fixed memory location, which is what it appears to be doing.

Setting today's date to NSDate

I have a NSDate property as below and I wish to set it with today's date.
#property (nonatomic, copy, readwrite) NSDate *todayDate;
I tried the following but I am getting an error:
NSDate *date = [[NSDate alloc] init];
self.todayDate = [date isToday];
I guess, isToday just checks whether the date is today's date and doesn't set the date.
I am getting following 2 errors:
Implicit conversion of 'BOOL' (aka 'signed char') to 'NSDate *' is disallowed with ARC
Incompatible integer to pointer conversion assigning to 'NSDate *' from 'BOOL' (aka 'signed char');
How do I set NSDate to today's date in Objective C?
NSDate has you covered:
NSDate *today = [NSDate date];
This is a common pattern in Apple's frameworks: semantic "factory" class methods. This call replaces your calls to alloc and init, and is a preferred way to work with common objects. It's also a nice pattern to emulate in your own classes :-)
On of the core concepts which should shed light on the "why" is that of immutability. Many objects (NSString, NSNumber, etc) are considered (at least in practice) to be immutable. This means they get their value exactly once: during init. This leads the the "other" answer also being an instantiation-time technique: a custom initializer.
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow: 0];
This will set your property to todays date. The error is because, as you suspect, you are assigning a boolean to a pointer.
self.todayDate = [NSDate date];

NSDate init question, related to memory management in Objective-C

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?
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.)
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];
}