Not able to resolve a leak detected by leaks tool. Can i ignore it? - iphone

I am not able to find a way to remove a leak detected by leaks tool.
Here is my problem...
I have a singleton object in my delegate which stores data on a global level. Now, I have a array of objects which i maintain here and add or modify it from controllers.
Below is a function which fills the objects and sets the above global array,
Now, the highlighted lines(marked by //LEAK) are where the leaks tool tell me its a leak. I require this array for my session. I release the array at the end when i logout.
Should i be worried about this kind leak?
-(LayoutInfo *) fillLayout: (GDataXMLElement *) layoutElement {
LayoutInfo *layout = [[LayoutInfo alloc] init];
layout.dataTableCount = 0;
layout.chartsCount = 0;
NSArray *templateNameArr = [layoutElement elementsForName:#"TemplateName"];
NSMutableArray *chartElements = [[NSMutableArray alloc] init]; // LEAK
NSMutableArray *dtElements = [[NSMutableArray alloc] init];
NSArray *charts = [layoutElement elementsForName:#"chart"]; // LEAK
if (charts.count > 0) {
for (GDataXMLElement *singleChart in charts) {
chart *chartInfo = [[chart alloc] init]; // LEAK
layout.chartsCount = layout.chartsCount + 1;
NSArray *imageName = [singleChart elementsForName:#"imageName"];
if (imageName.count > 0) {
GDataXMLElement *imageNameStr = (GDataXMLElement *) [imageName objectAtIndex:0];
chartInfo.imageName = imageNameStr.stringValue; // LEAK
}
NSArray *imagePath = [singleChart elementsForName:#"imagePath"];
if (imagePath.count > 0) {
GDataXMLElement *imagePathStr = (GDataXMLElement *) [imagePath objectAtIndex:0];
chartInfo.imagePath = imagePathStr.stringValue; // LEAK
}
NSArray *imageFileName = [singleChart elementsForName:#"imageFileName"];
if (imageFileName.count > 0) {
GDataXMLElement *imageFileNameStr = (GDataXMLElement *) [imageFileName objectAtIndex:0];
chartInfo.imageFileName = imageFileNameStr.stringValue;
}
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:chartInfo.imagePath]];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]
stringByAppendingPathComponent:chartInfo.imageFileName]];
[request setDidFinishSelector:#selector(fillLayout_requestDone:)];
[request setDidFailSelector:#selector(fillLayout_requestWentWrong:)];
[request startSynchronous];
NSString *imagePath1 = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:chartInfo.imageFileName];
if([[NSFileManager defaultManager] fileExistsAtPath:imagePath1]) {
NSLog(#" --- IMAGE SAVED -- %#", imagePath1);
}
[chartElements addObject:chartInfo];
} //for
layout.chartElement = chartElements; // THIS IS WHERE I ASSIGN THE GLOBAL ARRAY
//[chartElements release];
}
return layout;
}

-(LayoutInfo *) fillLayout: (GDataXMLElement *) layoutElement {
LayoutInfo *layout = [[LayoutInfo alloc] init];
layout.dataTableCount = 0;
layout.chartsCount = 0;
NSArray *templateNameArr = [layoutElement elementsForName:#"TemplateName"];
NSMutableArray *chartElements = [[NSMutableArray alloc] init]; // LEAK
//NSMutableArray *dtElements = [[NSMutableArray alloc] init];
NSArray *charts = [layoutElement elementsForName:#"chart"]; // LEAK
if (charts.count > 0) {
for (GDataXMLElement *singleChart in charts) {
chart *chartInfo = [[chart alloc] init]; // LEAK
layout.chartsCount = layout.chartsCount + 1;
NSArray *imageName = [singleChart elementsForName:#"imageName"];
if (imageName.count > 0) {
GDataXMLElement *imageNameStr = (GDataXMLElement *) [imageName objectAtIndex:0];
chartInfo.imageName = imageNameStr.stringValue; // LEAK
}
NSArray *imagePath = [singleChart elementsForName:#"imagePath"];
if (imagePath.count > 0) {
GDataXMLElement *imagePathStr = (GDataXMLElement *) [imagePath objectAtIndex:0];
chartInfo.imagePath = imagePathStr.stringValue; // LEAK
}
NSArray *imageFileName = [singleChart elementsForName:#"imageFileName"];
if (imageFileName.count > 0) {
GDataXMLElement *imageFileNameStr = (GDataXMLElement *) [imageFileName objectAtIndex:0];
chartInfo.imageFileName = imageFileNameStr.stringValue;
}
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:chartInfo.imagePath]];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]
stringByAppendingPathComponent:chartInfo.imageFileName]];
[request setDidFinishSelector:#selector(fillLayout_requestDone:)];
[request setDidFailSelector:#selector(fillLayout_requestWentWrong:)];
[request startSynchronous];
NSString *imagePath1 = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:chartInfo.imageFileName];
if([[NSFileManager defaultManager] fileExistsAtPath:imagePath1]) {
NSLog(#" --- IMAGE SAVED -- %#", imagePath1);
}
[chartElements addObject:chartInfo];
[chartInfo release]; // it's retained in chartElements until removed, or until chartElements is deallocced
} //for
if(layout.charElement){
[layout.charElement release]; // you should however consider in making charElement property as retain;
layout.charElement = nil; // this isn't required here (since you're assigning it a new value), but you should usually set it to nil after a release to prevent EXC_BADACCESS
}
layout.chartElement = chartElements; // THIS IS WHERE I ASSIGN THE GLOBAL ARRAY
//[chartElements release];
}
return [layout autorelease]; // in case you don't want it autoreleased you should call your method something like: createFilledLayout ('create' is usually used so anyone that uses the method knows it's responsible for releasing the return value)
}
you should have a look at Memory Management Programming Guide

Related

Parsing RSS feed - retrieve images, urls?

Hello I am parsing a RSS And Atom feeds, and my question is how can I check for < img > and < url > tags in < description >?
There must be some sort of check. Thanks.
Here is how I parse them:
- (NSArray *)parseFeed:(NSURL *)feedURL{
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:feedURL];
GDataXMLDocument *xmlParse = [[GDataXMLDocument alloc] initWithData:data error:&error];
GDataXMLElement *rootElement = xmlParse.rootElement;
NSArray *array = [[NSArray alloc] init];
if ([rootElement.name compare:#"rss"] == NSOrderedSame) {
array = [self parseRSSFeed:rootElement];
return array;
} else if ([rootElement.name compare:#"feed"] == NSOrderedSame) {
array = [self parseAtomFeed:rootElement];
return array;
} else {
NSLog(#"Unsupported root element: %#", rootElement.name);
return nil;
}
}
-(NSArray *)parseRSSFeed:(GDataXMLElement *) rootElement
{
NSMutableArray *entries = [[NSMutableArray alloc] init];
NSArray *channels = [rootElement elementsForName:#"channel"];
for (GDataXMLElement *channel in channels) {
NSArray *items = [channel elementsForName:#"item"];
for (GDataXMLElement *item in items) {
FeedItem *itemF = [[FeedItem alloc] init];
itemF.title = [item valueForChild:#"title"];
itemF.description = [item valueForChild:#"description"];
NSLog(#"IMAGE - %#", [item valueForChild:#"img"]);
itemF.dateString = [item valueForChild:#"pubDate"];
itemF.link = [NSURL URLWithString:[item valueForChild:#"link"]];
itemF.dateString = [item valueForChild:#"updated"];
itemF.author = [item valueForChild:#"author"];
[entries addObject:itemF];
NSLog(#"RSS - %#", itemF.title);
}
}
NSArray *RSSArray = [entries copy];
return RSSArray;
}
-(NSArray *)parseAtomFeed:(GDataXMLElement *) rootElement
{
NSMutableArray *entries = [[NSMutableArray alloc] init];
NSArray *entry = [rootElement elementsForName:#"entry"];
for (GDataXMLElement *entryElement in entry) {
// NSArray *items = [channel elementsForName:#"item"];
//for (GDataXMLElement *item in items) {
FeedItem *itemF = [[FeedItem alloc] init];
itemF.title = [entryElement valueForChild:#"title"];
itemF.description = [entryElement valueForChild:#"summary"];
NSArray *links = [entryElement elementsForName:#"link"];
for (GDataXMLElement *link in links) {
itemF.link = [NSURL URLWithString:[[link attributeForName:#"href"] stringValue]];
}
itemF.dateString = [entryElement valueForChild:#"updated"];
NSArray *authors = [entryElement elementsForName:#"author"];
for (GDataXMLElement *authorElement in authors) {
itemF.author = [authorElement valueForChild:#"name"];
}
[entries addObject:itemF];
NSLog(#"Atom - %#", itemF.title);
}
NSArray *atomArray = [entries copy];
return atomArray;
}
I am parsing them using GDataXMLParser, and my own parser class.
Do it like this:
NSString *Str=[item valueForChild:#"description"];
NSArray *tmp=[Str componentsSeparatedByString:#"<Img>"];
if([tmp count]>1){
NSString *urlstr=[[tmp objectatindex:1] stringByReplacingOccurrencesOfString:#" </Img>" withString:#""];
}
Now urlstr contains your image url.
Enjoy
I thought that
itemF.description = [item valueForChild:#"description"];
is NSString. So you can use componentsSeparatedByString with "your tag".
It will return array. In array at postion 1 you will get your img url.
This url has closing bracket "your closing tag".
Replace "your closing tag" with space. You will get image url.
Hope, this will help you.

read and write using NSKeyedArchiver, ios

Below is a class to read and write data using nsarchive
Data.m
-(id)init {
self = [super init];
if(self) {
arr = [[NSMutableArray alloc] init];
}
return self;
}
-(NSString *)getPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath;
if ([paths count] > 0)
documentPath = [paths objectAtIndex:0];
NSString *draftDataPath = [documentPath stringByAppendingPathComponent:#"draftData.dat"];
return draftDataPath;
}
-(void)saveDataToDisk {
NSString *path = [self getPath];
[NSKeyedArchiver archiveRootObject:arr toFile:path];
}
-(void)loadDataFromDisk {
NSString *path = [self getPath];
self.arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
}
At later on, I am adding some objects into arr by doing
CustomerClass.m
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data.arr addObject:myObject1]
[data.arr addObject:myObject2]
[data.arr addObject:myObject3]
[data saveDataToDisk];
}
At DisplayData.m, I want to check data.arr by
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data loadDataFromDisk];
NSLog(#"length of array is %d",[data.arr count]);
}
On the console, I am getting
length of array is 1
I thought it should be 3 after all.
Please point out what I have just made a mistake in the middle of work if you have any clues about it.
So, I suspect that your "myObjects" are not NSCoding compliant. I just did this:
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:3];
[arr addObject:#"Hello"];
[arr addObject:#" "];
[arr addObject:#"World"];
BOOL ret = [NSKeyedArchiver archiveRootObject:arr toFile:[self getPath]];
NSArray *arr2 = [NSKeyedUnarchiver unarchiveObjectWithFile:[self getPath]];
NSLog(#"count = %d", [arr2 count]);
And the results was "count = 3"
I feel like there's too much code here to do what you're looking for. I think all you need is:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dataClass] forKey:NSUserDefaultString];
[[NSUserDefaults standardUserDefaults] synchronize];
to save it.
And:
NSData *someData = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaultString];
if (settingsData != nil)
{
dataClass = [NSKeyedUnarchiver unarchiveObjectWithData:settingsData];
}
to retrieve it.

how to parse gdata xml in iPhone?

here is xml
Root--->
Subject--->
SubjectID 1 /SubjectID
SubjectName MatheMatics /SubjectName
Sub_Subject---->
Sub_SubjectID 1 /Sub_SubjectID
Sub_SubjectName Calculus /Sub_SubjectName
/Sub_Subject
Sub_Subject
Sub_SubjectID 2 /Sub_SubjectID
Sub_SubjectName Geometry /Sub_SubjectName
/Sub_Subject
/Subject
Subject---->
SubjectID 2 /SubjectID
SubjectName Physics /SubjectName
/Subject
/Root
in app i want to show subject name in tableviewcontroller when application launch & when we clicked on tableviewcell it leads on another table view which shows sub_subject list.
how to achieve this
for that.
+ (NSString *)dataFilePath:(BOOL)forSave {
return [[NSBundle mainBundle] pathForResource:#"SubjectData" ofType:#"xml"];
}
+ (RootSubject *)loadParty {
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
/* if (doc == nil) { return nil; }
NSLog(#"%#", doc.rootElement);
[doc release];
[xmlData release];
return nil;*/
RootSubject *rootSubject = [[[RootSubject alloc] init] autorelease];
NSArray *partyMembers = [doc nodesForXPath:#"//Root/Subject" error:nil];
//NSArray *patry = [doc nodesForXPath:#"//Root/Subject/SunjectID" error:nil];
for (GDataXMLElement *partyMember in partyMembers) {
// Let's fill these in!
NSString *subjectId, *subjectName, *sub_SubjectId, *sub_SubjectName;
// senderName
NSArray *subjectIds = [partyMember elementsForName:#"SubjectID"];
if (subjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [subjectIds objectAtIndex:0];
subjectId = firstName.stringValue;
} else continue;
// senderEmail
NSArray *subjectNames = [partyMember elementsForName:#"SubjectName"];
if (subjectNames.count > 0) {
GDataXMLElement *firstLevel = (GDataXMLElement *) [subjectNames objectAtIndex:0];
subjectName = firstLevel.stringValue;
} else continue;
/* //senderPhone
NSArray *sub_SubjectIds = [partyMember elementsForName:#"Sub_SubjectID"];
if (sub_SubjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectIds objectAtIndex:0];
sub_SubjectId = firstName.stringValue;
} else continue;
//senderLocation
NSArray *sub_SubjectNames = [partyMember elementsForName:#"Sub_SubjectName"];
if (sub_SubjectNames.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectNames objectAtIndex:0];
sub_SubjectName = firstName.stringValue;
} else continue;*/
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:nil sub_SubjectName:nil]autorelease];
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:nil sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
//[rootGroup.groups addObject:group];
[rootSubject.subjects addObject:subject];
}
[doc release];
[xmlData release];
return rootSubject;
}
through this we get subject name and show it perfectly in tableviewcontroller but when i clicked on particular subject which provides subsubject in another view controller
Here is a good tutorial that shows XML parsing using GDataXMLParser.
how-to-read-and-write-xml-documents-with-gdataxml

Memory Leak related

i am working on a fishing app these days and i am getting a memory leak problem
-(void)requestFinished:(ASIFormDataRequest *) request {
if(hud != nil){
[hud show:NO];
[hud release];
hud = nil;
}
isLoading = NO;
self.responseText = [request responseString];
[self parseXml]; //I am getting leak here
if ( [self.responseText hasPrefix:#"<result>"]) {
UIAlertView *info = [[[UIAlertView alloc] initWithTitle:#" " message:#"Limited Internet access, please find a stronger signal in the area" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil]autorelease];
[info show];
}
if (!isRefreshButtonClicked) {
[UIAccelerometer sharedAccelerometer].delegate = self;
[NSThread detachNewThreadSelector:#selector(parseXml) toTarget:self withObject:nil];
} }
This is my function...
-(void) parseXml
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
_fishes = [[fishes parseXml:self.responseText] retain];
[self performSelectorOnMainThread:#selector(parseXmlDone) withObject:nil waitUntilDone:YES];
[pool release];
Here _fishes is an array which is getting a value from a array return type function.....and here is that function...
+(NSMutableArray *)parseXml:(NSString *)xmlString {
//xmlString = [xmlString stringByReplacingOccurrencesOfString:#"&" withString:#""];
const char *cString = [xmlString UTF8String];
NSMutableArray *fishes = [NSMutableArray array];
NSData *xmlData = [NSData dataWithBytes:cString length:strlen(cString)];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; }
//parseXml
NSArray *_fishes = [doc.rootElement elementsForName:#"fishery"];
for (GDataXMLElement *_fish in _fishes) {
NSMutableDictionary *fish = [NSMutableDictionary dictionary];
NSArray *ids = [_fish elementsForName:#"id"];
if ([ids count]>0) {
GDataXMLElement *firstId = (GDataXMLElement *)[ids objectAtIndex:0];
[fish setValue:firstId.stringValue forKey:#"id"];
} else continue;
NSArray *names = [_fish elementsForName:#"name"];
if ([names count]>0) {
GDataXMLElement *firstName = (GDataXMLElement *)[names objectAtIndex:0];
[fish setValue:firstName.stringValue forKey:#"name"];...........
........
else continue;
NSArray *distances = [_fish elementsForName:#"distance"];
if ([distances count]>0) {
GDataXMLElement *distance = (GDataXMLElement *)[distances objectAtIndex:0];
[fish setValue:distance.stringValue forKey:#"distance"];
}else continue;
[fishes addObject:fish];
}
[doc release];
return fishes;
}
#end
I hope u guys will understand my problem...thanx
In -parseXml,
_fishes = [[fishes parseXml:self.responseText] retain];
will leak any previous object _fishes was pointing to in case -parseXml is sent more than once. You could use a retain property instead of an instance variable, or a setter method that releases the previous object, or release the previous object before assigning a new (retained) object to _fishes.

Find out when all processes in (void) is done?

I need to know how you can find out when all processes (loaded) from a - (void) are done, if it's possible.
Why? I'm loading in data for a UITableView, and I need to know when a Loading... view can be replaced with the UITableView, and when I can start creating the cells.
This is my code:
- (void) reloadData {
NSAutoreleasePool *releasePool = [[NSAutoreleasePool alloc] init];
NSLog(#"Reloading data.");
NSURL *urlPosts = [NSURL URLWithString:[NSString stringWithFormat:#"%#", URL]];
NSError *lookupError = nil;
NSString *data = [[NSString alloc] initWithContentsOfURL:urlPosts encoding:NSUTF8StringEncoding error:&lookupError];
postsData = [data componentsSeparatedByString:#"~"];
[data release], data = nil;
urlPosts = nil;
self.numberOfPosts = [[postsData objectAtIndex:0] intValue];
self.postsArrayID = [[postsData objectAtIndex:1] componentsSeparatedByString:#"#"];
self.postsArrayDate = [[postsData objectAtIndex:2] componentsSeparatedByString:#"#"];
self.postsArrayTitle = [[postsData objectAtIndex:3] componentsSeparatedByString:#"#"];
self.postsArrayComments = [[postsData objectAtIndex:4] componentsSeparatedByString:#"#"];
self.postsArrayImgSrc = [[postsData objectAtIndex:5] componentsSeparatedByString:#"#"];
NSMutableArray *writeToPlist = [NSMutableArray array];
NSMutableArray *writeToNoImagePlist = [NSMutableArray array];
NSMutableArray *imagesStored = [NSMutableArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]];
int loop = 0;
for (NSString *postID in postsArrayID) {
if ([imagesStored containsObject:[NSString stringWithFormat:#"%#.png", postID]]){
NSLog(#"Allready stored, jump to next. ID: %#", postID);
continue;
}
NSLog(#"%#.png", postID);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[postsArrayImgSrc objectAtIndex:loop]]];
// If image contains anything, set cellImage to image. If image is empty, try one more time or use noImage.png, set in IB
if (imageData == nil){
NSLog(#"imageData is empty before trying .jpeg");
// If image == nil, try to replace .jpg with .jpeg, and if that worked, set cellImage to that image. If that is also nil, use noImage.png, set in IB.
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[postsArrayImgSrc objectAtIndex:loop] stringByReplacingOccurrencesOfString:#".jpg" withString:#".jpeg"]]];
}
if (imageData != nil){
NSLog(#"imageData is NOT empty when creating file");
[fileManager createFileAtPath:[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:#"images/%#.png", postID]] contents:imageData attributes:nil];
[writeToPlist addObject:[NSString stringWithFormat:#"%#.png", postID]];
} else {
[writeToNoImagePlist addObject:[NSString stringWithFormat:#"%#", postID]];
}
imageData = nil;
loop++;
NSLog(#"imagePlist: %#\nnoImagePlist: %#", writeToPlist, writeToNoImagePlist);
}
NSMutableArray *writeToAllPlist = [NSMutableArray arrayWithArray:writeToPlist];
[writeToPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:nowPlist]];
[writeToAllPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]]];
[writeToNoImagePlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"]]];
[writeToPlist writeToFile:nowPlist atomically:YES];
[writeToAllPlist writeToFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"] atomically:YES];
[writeToNoImagePlist writeToFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"] atomically:YES];
[releasePool release];
}
It is as simple as returning a bool at the bottom of the selector being run in the background, and reaload the UITableView.
Thanks to #iWasRobbed:
I have never done this, but just speculating: have you tried returning a BOOL at the very end so that the reloadData function will return TRUE when it gets to that point? I am assuming (possibly incorrectly) that the device serially handles tasks one-at-a-time, so give it a shot.