Why do I need to retain the result of NSDateFormatter dateFromString: - objective-c

I have an NSDate* that I'm storing as a property with the retain keyword:
#property (nonatomic, retain) NSDate* startTime;
I use it as follows:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"h:mm a"];
startTime = (NSDate*)[[NSUserDefaults] standardUserDefaults] objectForKey:#"StartTimeKey"];
if (startTime == nil)
startTime = [[dateFormatter dateFromString:#"8:00 am"] retain];
Why do I need to retain the result of the dateFromString: message, but I don't need to retain the result of objectForKey: ?
I just upgraded to XCode 4.2 and I'm now using the LLVM GCC 4.2 compiler. Before the upgrade, the code worked fine without the retain. Now it crashes (later in the code when I access the startDate property) without the retain message.

The problem is that you wrote this:
startTime = blah blah blah;
You're setting the instance variable startTime directly. If you do this instead:
self.startTime = blah blah blah;
then the compiler will turn it into this:
[self setStartTime:blah blah blah];
and the automatically-generated setter method will do the retain for you.
If you do this:
#synthesize startTime = _startTime;
then the instance variable will be named _startTime, making it easier to remember to use the property instead of assigning to the instance variable directly.

The answer is in the Memory Management Programming Guide on page 11.
You own an object you create (that is you do not need to retain it, it has been done ). You create an object with alloc, new, copy or mutablecopy.
In this case, the dateFormatter gives you a new object but, since you did not call alloc, new or copy yourself, dateFormatter will call (normally its how it works) autorealease on the new NSDAte object.
But, if you were setting your property using the setter and getter, you would no have this problem.

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.

Objective-C Property assignment without #property

I'm currently developing an iOS application which was started by another developer.
Usually, I make a property for every instance variable (assign for int, bool etc. / retain for all classes).
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
So I use:
NSString *tmpMyVar = [[NSString alloc] init];
[self setMyVar: tmpMyVar];
[tmpMyVar release];
Or:
NSString *tmpMyVar = [[[NSString alloc] init] autorelease];
[self setMyVar: tmpMyVar];
In this new project, the previous developer didn't use #property/#synthesize so I'm wondering what will be the result of the previous line of code in this context (it doesn't call setter I guess)? Memory Leak?
The previous developer releases variable in dealloc method, just like me.
Thank you very much!
Since it directly assigns the instance variable to the allocated object it's retain count is 1 (because, like you said, a setter isn't called).
And because it's released in dealloc, it's all balanced out. So no memory leaks.
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
No,it wouldn't even in your projects, because, as you pointed out, no setter is used.
Also, when using properties, it is the recommended way to access instance variables directly in the init method, instead of using setters.
To inspect for questionable memory-leaks like your example, also use the clang static analyzer or instrument's leak tool.
You need to look at the other developer's setter implementation. Make sure they release the existing value and retain the new value; something like:
- (void)setMyString:(NSString *)string
{
[string retain];
[_string release]; // ivar
_string = string;
}
The only advantage to implementing your own setter/getter methods is to do something (other than setting the ivar) when a value is set. If the methods don't do anything like this then why not change all implementations to #property/#synthensize?

Copying NSDate objects and releasing

if I do this:
NSDate *dateStart;
[dateStart alloc];
// Initialise with a date somewhere here..
..
// Modify the start date.
dateStart = [chosenDate copy];
Should I be doing a [dateStart release] before assigning the dateStart pointer?
I'm from a C/C++ background and I don't understand the whole ObjectiveC/iOS garbage collection behaviour (if indeed there is any). My C background is telling me I should be freeing the initial NSDate object that dateStart is pointing to. Would that be correct?
Yes since you allocated it before you should release it before this line
//Release it before reassign
[dateStart release];
dateStart = [chosenDate copy];
Also notice that its preferred that you do the allocation and initialization on the same line, dont break them to multiple lines
So this
NSDate *dateStart;
[dateStart alloc];
Would change to
NSDate *dateStart = [[dateStart alloc] init....];

I haven't understood weak and strong references

By books first explains the problem (using ARC) about "unvalid" references, like in this example:
NSDate* date1=[[NSDate alloc]init];
NSDate* date2=date1;
[date1 release];
NSLog(#"%#",date2); // bad access
So I have understood the retain/release mechanism: in this case the instruction would be:
date2=[date1 retain];
But when it talks about strong/weak references, it sounds like a contradiction to me:
"By default, references are strong. If you assign an object to a strong reference, ARC assumes that you want that object to stick around and retains it implicitly"
Isn't this a contradiction of what has said before?
date2 is strong by default, so it should implicitly retain date1 and there wouldn't be a bad access exception.
Of course I have misunderstood something, could someone explain this better to me?
Strong is the default because it's typically what you want, but using ARC, the compiler analyzes how long the object's life needs to be and releases the memory at the appropriate time. For example:
- (void)someMethod
{
NSDate* date = [[NSDate alloc] init]; // date is __strong by default
NSLog(#"The date: %#", date); // date still contains the object created above
// Sometime before this point, the object date pointed to is released by the compiler
}
Weak references only keep the object around while it has one or more other strong references to it. As soon as the last strong reference is broken, the object is released by the compiler and the weak object reference (the variable) is changed to nil by the runtime. This makes weak variables almost useless in the local scope like the example above. For example:
- (void)someMethod
{
__weak NSDate* date = [[NSDate alloc] init]; // The date created is released before it's ever assigned to date
// because date is __weak and the newly created date has no
// other __strong references
NSLog(#"The date: %#", date); // This always prints (null) since date is __weak
}
To see an example of a weak and strong variable working together in the local scope (this would have only severely limited usefulness and is really shown here only to demonstrate weak variable references):
- (void)someMethod
{
NSDate* date = [[NSDate alloc] init]; // date stays around because it's __strong
__weak NSDate* weakDate = date;
// Here, the dates will be the same, the second pointer (the object) will be the same
// and will remain retained, and the first pointer (the object reference) will be different
NSLog(#"Date(%p/%p): %#", &date, date, date);
NSLog(#"Weak Date(%p/%p): %#", &weakDate, weakDate, weakDate);
// This breaks the strong link to the created object and the compiler will now
// free the memory. This will also make the runtime zero-out the weak variable
date = nil;
NSLog(#"Date: %#", date); // prints (null) as expected
NSLog(#"Weak Date: %#", weakDate); // also prints (null) since it was weak and there were no more strong references to the original object
}
The key mistake is in colluding manual-retain-release behavior and ARC as being identical. It isn't. Under ARC, object assignments are both atomic and, in and of themselves, expressions that determine object lifecycle.
Take your example and remove the retain. You end up with this:
NSDate* date1=[[NSDate alloc]init];
NSDate* date2=date1;
NSLog(#"%#",date2);
Makes perfect sense under ARC; there is no manual release screwing things up. I.e. it automatically just works.
Better yet, because the compiler does the flow control analysis behind the scenes, there is no extra retains or releases needed. The code will literally be something like:
NSDate* date1; // date1 initialized to nil -- or not given that it is never read before...
date1 = [[NSDate alloc]init]; // ... this assignment (of a +1 retain count obj)
NSDate* date2=date1; // retain count unchanged
NSLog(#"%#",date2); // retain count unchanged
.... compiler emits equivalent to [date1 release] ...
Since the compiler won't emit that release until after the last use of date1 or date2, there can never be a dangling pointer.

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];
}