iphone/ipad memory leak from NSString assigned to itself - iphone

I have two leaks shown by the instruments tool. I have looked around on google but I haven't seen exactly my problem on there.
Problem #1:
self.wallText = [[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
I have tried various configurations of the above line but all leak. I need to do both those trimming operations. 'text' is declared with either #"" or stringWithFormat.
My other issue is with the following line:
NSString * value = [elements objectAtIndex:i+1];
if ([value length] >= 2 && [[value substringToIndex:2] isEqualToString:#"S_"]){
value = [value substringFromIndex:2]; // LEAK HERE
}
I need to get all of the string except for the first 2 characters so I don't know how I could release it first or something... if that is indeed what I should be doing.
I could get away wtih leaks before with previous projects but this one is very memory intensive and I need all the memory I can get!
Any pointers would be greatly appreciated

Did you declare #property (retain) for wallText, did you do [wallText release] in dealloc method?
Double check above things and you will not have leaks any more
For Updated Part:
It is really strange that you have a memory leak there. Because at first, your value points to an autoreleased object then it points to another autoreleased object which I think is fine.

have u use alloc for value. value = [value substringFromIndex:2]; .here now value is referencing to new autorelease string. so u can not release previous object.

Related

Memory leak when declaring NSString from ABRecordCopyValue

I am using the following line of code...
NSString *clientFirstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
The 'analyse' feature on Xcode is saying that this giving rise to a potential memory leak. I am not releasing clientFirstName at all as I have neither alloc or retain'd it.
However, I am conscious that ABRecordCopyValue may not be returning an object as say a command like [NSMutableArray arrayWithArray:someArray] would which might mean I am indeed creating a new object that I control and must release.
Keen to hear thoughts...
Any sort of copy returns an object with a retainCount of 1, so you need to release it via CFRelease().
See the doc:
You are responsible for releasing this object.
Refer to this link. It has same as yours:
NSString potential leak
Refer to answer of KennyTM:
ABMultiValueCopyValueAtIndex is a "Copy" function, which follows
the "Create
Rule".
You need to call CFRelease to release it after finish using it.
NSString *contactEmail = (NSString *)ABMultiValueCopyValueAtIndex(emailInfo, 0);
...
if (contactEmail != nil)
CFRelease((CFTypeRef) contactEmail);
Release your object clientFirstName using CFRelease.
Add the code below:
if(clientFirstName != nil)
{
CFRelease((CFTypeRef) clientFirstName);
}
NOTE: Do not forget to check if clientFirstName is not nil. It is better to have a practice of checking that object is not nil before executing any function on it as it saves us from potential crashes though not in this case, but in many cases
EDIT:
Also as #Dondragmer says in one of the comments below:
I think even
[clientFirstName release];
should solve the problem.
Let me know if you need more help.
Hope this helps you.
I don't fully understand how ObjectiveC reference counting works, but a small update in code fixed the Analyze warning:
Before:
NSString *firstName = (__bridge NSString*) ABRecordCopyValue(person, kABPersonFirstNameProperty);
After
NSString *firstName = (__bridge_transfer NSString*) ABRecordCopyValue(person, kABPersonFirstNameProperty);

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 Leaked Object Error

I'm getting a potentially leaked object error from the Static Analyzer for this line:
strCleanPhone = [[[[strPhone stringByReplacingOccurrencesOfString:#" " withString:#""]
stringByReplacingOccurrencesOfString:#"(" withString:#""]
stringByReplacingOccurrencesOfString:#")" withString:#""]
stringByReplacingOccurrencesOfString:#"-" withString:#""];
For one, is this the preferred way to strip non-numeric characters from a phone number string?
Two, can you possibly explain why this would be a leaked object?
The strings created by stringByReplacingOccurrencesOfString are autoreleased, so they aren't leaked. If there's a leak, it has to do with strPhone and strCleanPhone.
For example, if strCleanPhone is a #property with the retain option, and is currently not nil, then your code leaks it. To use the release/retain code that was generated by synthesize you have to use the property syntax: self.strCleanPhone = .... Using just strCleanPhone = ... sets the instance variable and doesn't release any object it was pointing to.
If you're on iOS 4.0+, you might be able to use the new NSRegularExpression object to do this a little more elegantly.
The code you have as posted doesn't leak. It just creates four autoreleased string objects.
If you are looking to strip out characters that are not numbers.
NSString *strPhone = #"(555) 444-3333";
NSMutableString *strCleanPhone = [NSMutableString string];
for (int i=0;i<[str length];i++)
{
unichar ch = [str characterAtIndex:i];
if (isnumber(ch)) [strCleanPhone appendFormat:#"%c", ch];
}
But I suggest looking into regular expressions.
Make sure you expand the analyzer warning by clicking the warning text in the source view! Chances are it's pointing to where a variable is last referenced; if you expand the warning you'll see a bunch of arrows indicating code flow, which will help indicate where you've allocated your potentially-leaked object.
(tl;dr: Post more code.)

how do i swap two NSString variables (in a non garbage collected environment)?

I'm trying to swap two strings but I'm not sure if what I am doing is legal (coming from java I'm new to the whole retain count memory management).
Here's my code:
NSString *temp = [[NSString alloc] init];
temp = originalLanguageCode;
originalLanguageCode = translatedLanguageCode;
translatedLanguageCode = temp;
[temp release];
Is this allowed? I'm getting some strange bugs and I'm not sure what's causing them, hoping that this might be it. Any help is very appreciated, thanks!
After assigning a newly allocated string to temp you are immediately assigning originalLanguageCode to it, so the allocated string is completely lost. That is a memory leak. Then you are releasing temp, which was originally originalLanguageCode. This is an over-release.
Try this instead:
NSString *temp = originalLanguageCode;
originalLanguageCode = translatedLanguageCode;
translatedLanguageCode = temp;
Everything looks fine except that in your first line you're creating a string which you immediately leak on the second. You can just say:
NSString *temp = originalLanguageCode;
...
... and get rid of the [temp release] since you didn't create (and don't own) the object assigned to "temp."
Now you didn't say whether originalLanguageCode and translatedLanguageCode are instance variables. If so, use their accessors (which should themselves be doing the right thing with memory management).

memory leak in iPhone Obj C code

I'm parsing an XML string and have a memory leak. I know this code is leaking, but not sure what the fix is:
http://pastie.org/580694
Code like this appears to be fundamentally flawed:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)value{
if ([currentElement isEqualToString:#"problem_id"]){
currentProblem.problemId = [[value copy] intValue];
} else if ([currentElement isEqualToString:#"rule_instance_id"]){
currentProblem.ruleInstanceId = [value copy];
} else if ([currentElement isEqualToString:#"description"]){
currentProblem.desc = [value copy];
} else if ([currentElement isEqualToString:#"name"]){
currentProblem.name = [value copy];
but not sure how I should deal with grabbing the found characters and retaining/releasing them.
thanks
In the definition of the Problem class, let the compiler deal with property memory management for you:
Define string properties with #property (retain) NSString *desc;. This will make sure your class increments the reference count on string values it stores (and decrement it if another value is stored later on).
Define int properties with #property (assign) int problemId. Ints don't need to be copied of ref-counted.
In the dealloc: method, make sure to release all the retained properties, e.g. [desc release].
Finally, you do not need to copy value before assigning to currentProblem's properties. currentProblem.desc = value will do the right thing. If you leave [value copy] in place, that would keep on leaking.
As for the code in the question, it leaks in a couple of places:
[[value copy] intValue] leaks each time parser:foundCharacters: is called, as the copy is never released.
The string members of currentProblem leak when currentProblem is released, as the current implementation of dealloc: does not release them.
currentProblem.problemId = ... is equivalent to [currentProblem setProblemId:...]. You have almost certainly declared problemId to have a retain or copy setter, so setProblemId: retains the object passed. This is normal and good.
currentProblem.desc = [value copy];
-copy is one of the three magic words, which means the returned value is retained, and then you retain it again in the setter. So you are double-retaining; memory leak.
value is an NSString, so is immutable. There is no reason to make a copy of it. Many pointers may share an immutable object safely. This code should be:
currentProblem.desc = value;
This line is a little different:
currentProblem.problemId = [[value copy] intValue];
In this case, problemId is clearly an assign property (or you would quickly crash), but you're still calling -copy on value, causing its retain count to go up by one, thus leaking it. This code should be:
currentProblem.problemId = [value intValue];
In short, stop copying the objects here and your memory leak will go away. Copying is somewhat rare in ObjC.