Potential leak of an object in objective c - objective-c

In my application in xml parsing method found character delegate method i use the fallowing code
NSString *Str = [[[NSString alloc] initWithString:foundString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] ;
if ([weekNames containsObject:elementName]) {
// if (!settings) {
// NSMutableDictionary *dict1=[[NSMutableDictionary alloc]initWithObjectsAndKeys:#"",#"no",#"بسم الله الرحمن الرحيم",#"surah",nil];
// [weekDict insertObject:dict1 atIndex:0];
//}
[array1 addObject:weekDict];
}
if ([elementName isEqualToString:#"DUA"]) {
[weekDict addObject:duaDict];
}
if ([elementName isEqualToString:#"NO"]) {
[duaDict setObject:Str forKey:#"no"];
}
if ([elementName isEqualToString:#"SURAH"]) {
[duaDict setObject:Str forKey:#"surah"];
}
foundString=nil;**
If i use this code in analyze application i got potent6ial memory leak.
If i autorelease the Str it will give too many times releasing .
Why it happens like that. Please any one help me.
Thanks in advance

This:
NSString *Str = [[[NSString alloc] initWithString:foundString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
really should be:
NSString *Str = [foundString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
What you are doing now is creating (alloc/init) a new NSString and then immediately leaking it, because you never actually save the pointer. And it turns out you never really needed that NSString to begin with.

Related

Objective-C Bad exception dropbox

I've got a question. Where is the reason for EXC_BAD_ACCESS in the following code ?
-(void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
if(metadata.isDirectory) {
db_Path = metadata.path;
int i = 0;
NSString *fileName = [[NSString alloc] init];
for(DBMetadata *file in metadata.contents) {
fileName = [NSString stringWithFormat:#"%#", file.filename];
[db_MetaFileNames addObject:file.filename];
i++;
}
[self createMetaListArray];
[fileName release];
}
}
-(void)createMetaListArray {
fileNamesAtDirectory = db_MetaFileNames;
for (int i=0; i < [fileNamesAtDirectory count]; i++) {
NSString *filePathWithName = db_directory;
[filePathWithName stringByAppendingFormat:
[fileNamesAtDirectory objectAtIndex:i]];
[filePathsAtDirectory addObject:filePathWithName];
[filePathWithName release];
}
}
Can Anyone here help me ?
Here:
NSString *fileName = [[NSString alloc] init];
for(DBMetadata *file in metadata.contents) {
fileName = [NSString stringWithFormat:#"%#", file.filename];
The NSString on the first line gets overwritten with the new values on the third line. The original value leaks.
This means that:
}
[self createMetaListArray];
[fileName release];
The release on the last line releases not the fileName that you alloc/init above, but the assignment inside the loop. You don't alloc/copy/retain that, so you're not "in charge" of releasing it.
You have a similar misunderstanding in the second function.
[filePathWithName stringByAppendingFormat:[fileNamesAtDirectory objectAtIndex:i]];
This does not amend filePathWithName. It returns a new string.
I suggest you read up on Cocoa's memory management rules -- you're missing some fundamentals. Understanding those will make your life a lot easier.

NSArray with componentsSeparatedByString memory leak

I'm having problems with memory leaks with this function. I thought creating an NSArray with componentsSeparatedByString was autorelease but instruments seems to indicate a leak at the NSArray aPair. Why would it indicate a leak there and not also at the other NSArrays created in the same way?
-(void) checkRequest: (NSString *)request view:(UIViewController *)theView webView:(UIWebView *)wView
{
//NSLog(#"JSResponder - checkRequest()");
NSString *aRequest = [NSString stringWithString:request];
NSArray *urlArray = [aRequest componentsSeparatedByString:#"?"];
if([urlArray count] > 1)
{
NSString *paramsString = [urlArray lastObject];
NSString *cmd = #"";
NSArray *urlParamsArray = [paramsString componentsSeparatedByString:#"&"];
int numCommands = [urlParamsArray count];
NSMutableDictionary *paramsWithNames = [[NSMutableDictionary alloc ] initWithCapacity:numCommands];
for (NSString *elementPair in urlParamsArray)
{
NSArray *aPair = [elementPair componentsSeparatedByString:#"="];
NSString *aKey = [aPair objectAtIndex:0];
NSString *aParam = [aPair objectAtIndex:1];
if([aKey compare:#"_command"] == NSOrderedSame)
{
cmd = aParam;
}
else
{
[paramsWithNames setValue: aParam forKey:aKey];
}
}
[self executeCommand: cmd withParams: paramsWithNames view:theView webView:wView];
[paramsWithNames release];
}
}
This function get called by the following:
- (void)pullJSEvent:(NSTimer*)theTimer
{
NSLog(#"MainView - pullJSEvent()");
NSString *jsCall = [NSString stringWithString:#"if(typeof checkOBJCEvents == 'function'){checkOBJCEvents();}"];
NSString *jsAnswer = [[webView stringByEvaluatingJavaScriptFromString:jsCall] retain];
if([jsAnswer compare:#"none"] != NSOrderedSame)
{
//NSLog(#" answer => %#", jsAnswer);
[jsResponder checkRequest:jsAnswer view:(UIViewController *)self webView:self.webView];
}
[jsAnswer release];
}
Thank-you
You're going to have to dig a bit deeper with the Leaks instrument. You're leaking one of the strings in the array, not the array itself. Leaks indicates that line because that's where the strings in the array are allocated.
Go into Leaks, look at a leaked instance, and click that little arrow button. You'll see all the retains and releases of the leaked object, which should point you to the problem.

release of previously deallocated object issue

I have a function which use for read one single line from a csv file.
But I got a release of previously deallocated object error, or sometimes the it is "double free" error.
I try to track down which object causes this error base on the error memory address, but I failed to do this.
Here's the code:
#interface CSVParser : NSObject {
NSString *fileName;
NSString *filePath;
NSString *tempFileName;
NSString *tempFilePath;
//ReadLine control
BOOL isFirstTimeLoadFile;
NSString *remainContent;
}
#property(nonatomic,retain) NSString *fileName;
#property(nonatomic,retain) NSString *filePath;
#property(nonatomic,retain) NSString *tempFileName;
#property(nonatomic,retain) NSString *tempFilePath;
#property(nonatomic,retain) NSString *remainContent;
-(id)initWithFileName:(NSString*)filename;
-(BOOL)checkAndCopyFile:(NSString *)filename;
-(BOOL)checkAndDeleteTempFile;
-(NSString*)readLine;
-(NSArray*)breakLine:(NSString*)line;
#end
#implementation CSVParser
#synthesize fileName;
#synthesize filePath;
#synthesize tempFileName;
#synthesize tempFilePath;
#synthesize remainContent;
-(id)initWithFileName:(NSString *)filename{
//ReadLine control
isFirstTimeLoadFile = TRUE;
self.fileName = filename;
self.tempFileName = [[NSString alloc] initWithFormat:#"temp_%#",fileName];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.filePath = [documentDir stringByAppendingPathComponent:fileName];
self.tempFilePath = [documentDir stringByAppendingPathComponent:tempFileName];
if ([self checkAndCopyFile:fileName]) {
return self;
}else {
return #"Init Failure";
}
}
-(BOOL)checkAndCopyFile:(NSString *)filename{
BOOL isFileExist;
NSError *error = nil;
NSFileManager *fileManger = [NSFileManager defaultManager];
isFileExist = [fileManger fileExistsAtPath:filePath];
if (isFileExist) {
//Create a temp file for reading the line.
[fileManger copyItemAtPath:filePath toPath:tempFilePath error:&error];
return TRUE;
}else {
return FALSE;
}
}
-(NSString*)readLine{
NSError *error = nil;
//Read the csv file and save it as a string
NSString *tempFirstLine = [[[NSString alloc] init] autorelease];
NSString *stringFromFileAtPath = [[NSString alloc] init];
if (isFirstTimeLoadFile) {
NSLog(#"Into First Time");
stringFromFileAtPath = [NSString stringWithContentsOfFile:tempFilePath
encoding:NSUTF8StringEncoding
error:&error];
isFirstTimeLoadFile = FALSE;
}else {
NSLog(#"Not First Time");
NSLog(#"Not First Time count:%d",[remainContent retainCount]);
stringFromFileAtPath = remainContent;
remainContent = nil;
}
if ([stringFromFileAtPath isEqualToString:#""]) {
[stringFromFileAtPath release];
return #"EOF";
}
//Get the first line's range
NSRange firstLineRange = [stringFromFileAtPath rangeOfString:#"\n"];
//Create a new range for deletion. This range's lenght is bigger than the first line by 1.(Including the \n)
NSRange firstLineChangeLineIncludedRange;
if (stringFromFileAtPath.length > 0 && firstLineRange.length == 0) {
//This is the final line.
firstLineRange.length = stringFromFileAtPath.length;
firstLineRange.location = 0;
firstLineChangeLineIncludedRange = firstLineRange;
}else {
firstLineRange.length = firstLineRange.location;
firstLineRange.location = 0;
firstLineChangeLineIncludedRange.location = firstLineRange.location;
firstLineChangeLineIncludedRange.length = firstLineRange.length + 1;
}
//Get the first line's content
tempFirstLine = [stringFromFileAtPath substringWithRange:firstLineRange];
remainContent = [stringFromFileAtPath stringByReplacingCharactersInRange:firstLineChangeLineIncludedRange withString:#""];
[stringFromFileAtPath release];
error = nil;
return tempFirstLine;
}
And the following code shows how I use the class above:
CSVParser *csvParser = [[CSVParser alloc] initWithFileName:#"test.csv"];
BOOL isFinalLine = FALSE;
while (!isFinalLine) {
NSString *line = [[NSString alloc] init];
line = [csvParser readLine];
if ([line isEqualToString:#"EOF"]) {
isFinalLine = TRUE;
}
NSLog(#"%#",line);
[line release];
}
[csvParser release];
If I run the code, and finish the csv parsing, the App's main function will give me the double free error when it try to free the autorelease pool."* __NSAutoreleaseFreedObject(): release of previously deallocated object (0x6a26050) ignored"
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
Could someone help me solve this issue?
Thank you!
[pool release];
Do not use -retainCount.
The absolute retain count of an object is meaningless.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
There are a few problems in your code:
you aren't following the correct init pattern. You should have a self = [super init...]; if (self) {...} in there somewhere.
tempFileName is a retain property and you assign it the result of alloc/init. It will be leaked.
An immutable empty string ([[NSString alloc] init]) is pretty much never useful. And, in fact, stringFromFileAtPath is being leaked (technically -- implementation detail wise there is an empty immutable singleton string and thus, no real leak, but.... still...)
Finally, the crash: your readLine method correctly returns an autoreleased object. Yet, your while() loop consuming the return value of readLine is also releaseing that return value, leading to a double-release and an attempt to free that which was already freed.
You should "build and analyze" your code. I bet the llvm static analyzer would identify most, if not all, of the problems I mentioned above (and probably some more I missed).
When building with the analyzer, do you have either "all messages" or "analyzer issues only" selected in the Build window? Because, looking at the code, I'm surprised the analyzer didn't catch the obvious problem with stringFromFileAtPath.
Excerpting the code, you have the following lines that manipulate stringFromFileAtPath:
NSString *stringFromFileAtPath = [[NSString alloc] init];
....
stringFromFileAtPath = [NSString stringWithContentsOfFile:tempFilePath
encoding:NSUTF8StringEncoding
error:&error];
....
stringFromFileAtPath = remainContent;
....
[stringFromFileAtPath release];
And remainContent is set by:
remainContent = [stringFromFileAtPath stringByReplacingCharactersInRange:firstLineChangeLineIncludedRange
withString:#""];
You are releasing an autoreleased object. By memory keeps going up, how are you measuring it? Don't use Activity Monitor as it is nearly as useless to developers as retainCount is misleading. Use Instruments.
Your tempFirstLine NSString object is declared with autorelease, and is returned as your NSString line, which is then released.
Try using this:
while (!isFinalLine) {
NSString *line = [csvParser readLine];
if ([line isEqualToString:#"EOF"]) {
isFinalLine = TRUE;
}
NSLog(#"%#",line);
}
Replac this:
NSString *stringFromFileAtPath = [[NSString alloc] init];
with this:
NSString *stringFromFileAtPath = nil;
and get rid of the [stringFromFileAtPath release] statements.
The first line creates a pointer to a new string object that you never use, because you immediately overwrite the pointer with a pointer to string objects from elsewhere, which you don't need to release because you don't own them/didn't create them. Since you are releasing them, you're getting a crash.
You make the same mistake with tempFirstLine.

Is there anything wrong with my code?

-(void)processGlyph:(int)glyphOne withGlyph:(int)glyphTwo
{
answer = glyphOne + glyphTwo;
NSString *tempText = [[NSString alloc] init];
tempText = [NSString stringWithFormat:#"%i",answer];
[self dispatchText:tempText];
[tempText release];
}
-(void)checkReadyToProcess
{
if (count >= 2) {
[self processGlyph:firstGlyph withGlyph:secondGlyph];
}
}
-(void)dispatchText:(NSString *) theText
{
answerText.text = theText;
}
Yes. It is here:
NSString *tempText = [[NSString alloc] init];//leaked
tempText = [NSString stringWithFormat:#"%i",answer];//creates new autoreleased object
...
[tempText release]; //causes an eventual crash
You are allocating an NSString, replacing the variable with an autoreleased NSString, and then releasing the autoreleased NSString. This will lead to a memory leak (from the original NSString) and a crash from over-releasing.
Instead, just do:
NSString *tempText = [NSString stringWithFormat:#"%i",answer];
You don't have to release it.

How do I convert an NSMutableString to NSString when using Frameworks?

I have written an Objective-C framework which builds some HTML code with NSMutableString which returns the value as an NSString.
I have declared an NSString and NSMutableString in the inteface .h file:
NSString *_outputLanguage; // Tests language output
NSMutableString *outputBuilder;
NSString *output;
This is a sample from the framework implementation .m code (I cannot print the actual code as it is proprietary):
-(NSString*)doThis:(NSString*)aString num:(int)aNumber {
if ([outputBuilder length] != 0) {
[outputBuilder setString:#""];
}
if ([_outputLanguage isEqualToString:#"html"]) {
[outputBuilder appendString:#"Some Text..."];
[outputBuilder appendString:aString];
[outputBuilder appendString:[NSString stringWithFormat:#"%d", aNumber]];
}
else if ([_outputLanguage isEqualToString:#"xml"]) {
[outputBuilder appendString:#"Etc..."];
}
else {
[outputBuilder appendString:#""];
}
output = outputBuilder;
return output;
}
When I wrote a text program, NSLog simply printed out "(null)". The code I wrote there was:
TheClass *instance = [[TheClass alloc] init];
NSString *testString = [instance doThis:#"This String" num:20];
NSLog(#"%#", testString);
[instance release];
I hope this is enough information!
I'm guessing that you're forgetting to alloc/init your strings...
Make sure outputBuilder is valid. Where are you alloc/init'ing it?
Your doThis: method doesn't seem to initialise outputBuilder. So if it is a null pointer, then nothing will be done to it.