Potential leak of an object allocated on line … - iphone

I am getting contact details and am having memory problems in my shouldContinueAfterSelectingPerson method. I followed a tutorial and did this weeks ago but now when I click Product -> Analyze I get 'Potential leak of an object allocated on line' on these 3 lines:
[lastName setText:(__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty)];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateOfBirth setText:birthday];
When clicking on these errors I get (though only number 2 for the third line):
Call to a function 'ABRecordCopyValue' returns a Core Foundation object with a + 1 retain count
Object leaked: allocated object is not referenced later in this execution path and has a retain count of + 1
The full code is shown below:
- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
[firstName setText:(__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty)];
[lastName setText:(__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty)];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMMM d, yyyy"];
birthday = [dateFormatter stringFromDate:(__bridge NSDate *)ABRecordCopyValue(person, kABPersonBirthdayProperty)];
[dateOfBirth setText:birthday];
Is there a fix around this and how important is it that I do fix it? I have one other potential leak of an object in my code.
A final note: I am using ARC.

You want this:
[lastName setText:(__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty)];
The reason you're seeing the warning from the analyser is that ABRecordCopyValue returns a CFStringRef with +1 retain count. You're then casting to an NSString* but saying to ARC not to take ownership of the object. That means it won't automatically add in the release for you. So you need to tell ARC to take ownership during the cast into Objective-C object land which is done using __bridge_transfer.
You could also have done:
CFStringRef string = ABRecordCopyValue(person, kABPersonLastNameProperty);
[lastName setText:(__bridge NSString *)string];
CFRelease(string);

Since the functions are returning new objects (they have copy in the name) you need to release those objects somehow.
This can be done by calling the appropriate method to release it, or by using __bridge_transfer instead of __bridge, which instructs ARC to take over the memory management and release it when needed.

Related

Variable memory address attribution EXEC_BAD_ACESS

I have an allocated object where its attributes are store in the following memory places:
When I make a simple attribution of the NSDate attribute to a variable it gives me an EXEC_BAD_ACESS.
As you can see from the first image only the date attribute and the fileDate variable have different addresses.
Am I making some pointer related error?
The other 2 attributes are assigned correctly to the variables, it only happens with the NSDate so maybe I'm missing some detail about NSDate.
EDIT1
DownloadFile definition:
EDIT2
init function:
EDIT3
date parameter:
Is there any reason why you are not using ARC? There are quite a few memory management errors there causing leaks and one that should cause your crash.
NSDate *dateFromString = [dateFormatter dateFromString:receivedDate];
returns an autoreleased NSDate so when you then call the additional
[dateFromString autorelease];
you are overreleasing the NSDate hence your crash.
[pFile setDate:[[NSDate alloc] init]];
is a memory leak. Going through the setter setDate: will cause pFile to take a +1 retain on the date, which it should release in it's dealloc. The [[NSDate alloc] init] call returns a date object with +1 but is then never released elsewhere.
You can fix this either with
[NSDate date]
Or
[[[NSDate alloc] init] autorelease];
The first option is preferred

retainCount shows MaxInt

After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger

Potential memory leak

I work on a project on iPhone iOS with Xcode 4.
With Xcode > Product >Analyze I get 35 issues, all of this type:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
and the problem is "Potential leak of an object allocated at ..."
What is the offending object and how can I release it?
Thanks
You're leaking the string that you're assigning to myTextField.text. When this assignment happens, a copy is being made (look at the property definition in the documentation). In most cases, when values are immutable, as is the case with NSStrings, a copy will give you an instance that points to the same location as the object that is being copied, with the retain count incremented by 1.
In the case of your code:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
The retain count of the string that you've allocated is 2.
You will either need to (1) release, (or autorelease) the string, or (2) use one of the NSString convenience methods, e.g. stringWithFormat: to create the string. This will give you an autoreleased string so you won't have to worry about explicitly releasing it.
(1)
NSString *str = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = str;
[str release]
or
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
(2)
myTextField.text = [NSString stringWithFormat:#"0.2f", abc]; // autoreleased
You are responsible for releasing string object you create here - as you use alloc/init for that.
The most convenient way here to set a string is to use class method +stringWithFormat that returns autoreleased string - so system will release that string object for you later:
myTextField.text = [NSString stringWithFormat:#"0.2f", abc];
Or you can write autorelease explicitly if you want:
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
If you don't want to use autorelease you can use temporary variable to create new string and release it after it was set for text field:
NSString *tempString = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = tempString;
[tempString release];
The thing is that UiTextFields's text property is declared as:
#property(nonatomic, copy) NSString *text
Therefore in this line:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
A new NSString is created with a retain count of 1, and then myTextField.text copies this object and increased its retain count by 1 or does it??, lets see what is happening:
A NSString object created with alloc initWithFormat with a retain count of 1
A NSString object with is a copy of the previous String, but because NStrings are immutable in this case, copy returns the same object!, therefore the NSString actually has a retain count of 2.

NSString *string = #"someString" vs NSString *string = [[NSString alloc] initWithFormat#"%#", string]

If I have a method
- (void) myMethod:(NSString *)string {
[Object anothermethodWithString:string];
}
and I call
[Object myMethod:#"this is a string with no alloc statement"]
Do I need to do something like
- (void) myMethod:(NSString *)string {
NSString *string2 = [[NSString alloc] initWithFormat:#"%#", string];
[Object anothermethodWithString:string2];
[string2 release];
}
instead of the way I had myMethod before? I have misbehaving code that seems to be caused by a string being auto-released while a second method within another method is being called (like in the example). The second way I have myMethod fixed all of my problems.
So is a "non-alloc" string an auto-released string? I asked this question as a follow up to another question (which was completely unrelated and is why I am creating this post), and a few sources said that I don't need to reallocate the string. I am confused, because the behavior of my code tells me otherwise.
Dave's got it right. You only need to worry about calling release on objects that you new, alloc, retain, or copy.
The above rule works very well, but if you're curious and want to get into a lot of detail, I suggest reading the Memory management Programming Guide from Apple's docs. It's free and goes from basic concepts into a lot of details.
If you use : NSString *str = #"". It is kind of a constant, you don't need to do any memory management.
If you call from a method : NSString *str = [NSString stringWithFormat:#""], the str is already autoreleased.
If you manually alloc, init. You need to call release, or autorelease yourself.
The general memory convention is : if you do something with new, alloc, retain, or copy, you need to release it yourself, any other cases, the object is autoreleased, don't release it

What is leaking in this statement using replaceObjectAtIndex

Instruments tells me the following line from the code below is leaking: I can't figure out how to fix this leak.
[self.selectedElement.usrAdvancedBuyingPercents replaceObjectAtIndex:selectedRow withObject:[numberFormatter stringFromNumber:percentage]];
- (IBAction) simpleMarginSliderValueChanged:(UISlider *)sender {
NSDecimalNumber *percentage = (NSDecimalNumber *)[NSDecimalNumber numberWithFloat:[sender value]];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setPositiveFormat:#"#.##"];
[self.selectedElement.usrAdvancedBuyingPercents replaceObjectAtIndex:selectedRow withObject:[numberFormatter stringFromNumber:percentage]];
[numberFormatter release];
}
The NSString you are creating from the number is not being released somewhere.
The problem is not in the code that is shown - it's somewhere else that is taking a string from that array, retaining it, then not releasing it. Leaks just shows you where memory that is leaked was initially allocated, and the only thing on that line that is allocating memory is [numberFormatter stringFromNumber:percentage].
Either that, or the whole array is not being released correctly (but then whatever builds usrAdvancedBuyingPercents would also show that is leaking).