开发者

More Leaks On My NSXMLParser :(

I will eventually get hold of this memory allocation idea and iphone development but i am struggling. Below is my code of my NSXMLParser for a twitter viewer i have made. It works fine and doesn't leak until about 30secs after the code is loaded... Its frustrating me because as soon as i get this parser done and without leaks I will be ready to go :).

I've watched loads of video tutorials and just need a help looking through my own code so i can get an idea.

rssParser.m

//
//  rssParser.m
//  template
//
//  Created by Jonathan Pink on 17/08/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "rssParser.h"


@implementation rssParser
@synthesize entries;


-(id)loadXMLData:(NSData *)xml{
    entries = [[NSMutableArray alloc] init];

    xmlParser = [[NSXMLParser alloc] initWithData:xml];
    [xmlParser setDelegate:self];
    [xmlParser parse];

    return self;
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{

    [currentElement release];
    currentElement = [elementName copy];

    if([elementName isEqualToString:@"item"])
    {
        RssData = [[rssData alloc] init];

        currentRssDescription = [[NSMutableString alloc] init];
        currentRssLink = [[NSMutableString alloc] init];
        currentRssPubDate = [[NSMutableString alloc] init];
        currentRssTitle = [[NSMutableString alloc] init];
    }

}


-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

    if([elementName isEqualToString:@"item"])
    {
        RssData.rssLink = currentRssLink;
        RssData.rssDescription = currentRssDescription;
        RssData.rssPubDate = currentRssPubDate;
        RssData.rssTitle = currentRssTitle;


        NSLog(@"currenttitle = %@",RssData.rssTitle);

    }
    if([elementName isEqualToString:@"item"])
    {
        [entries addObject:RssData];
        RssData = nil;

    }

}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{

    if([currentElement isEqualToString:@"title"])
    {
        [currentRssTitle appendString:string];
    }
    else if([currentElement isEqualToString:@"link"])
    {
        [currentRssLink appendString:string];
    }
    else if([currentElement isEqualToString:@"description"])
    {
        [currentRssDescription appendString:string];
    }
    else if([currentElement isEqualToString:@"pubDate"])
    {
        [currentRssPubDate appendString:string];
    }


}

- (void)parserDidEndDocument:(NSXMLParser *)parser {

    NSLog(@"all done!");
    NSLog(@"stories array has %d items", [entries count]);

}

-(void)dealloc{
    [currentElement release];
    [currentRssDescription release];
    [currentRssLink release];
    [currentRssPubDate release];
    [currentRssTitle release];

    [xmlParser release];
    [RssData release];
    [entries release];

    [super dealloc];
}



    @end

and the twitter view controller

//
//  TwitterViewController.m
//  template
//
//  Created by Jonathan Pink on 16/08/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "TwitterViewController.h"
#import "ASIHTTPRequest.h"


@implementation TwitterViewController


- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [config release];
    [RssParser release];
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(ProcessAndParse)];          
    self.navigationItem.rightBarButtonItem = anotherButton;
    [anotherButton release];

    numberOfTextRows = 4;
    config = [[Configuration alloc] init];
    [super viewDidLoad];
    [self ProcessAndParse];
    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}


-(void)ProcessAndParse{

    NSURL *url = [config urlForFeed:@"Twitter"];
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request setDelegate:self];
    [request startAsynchronous];

}

- (void)requestFinished:(ASIHTTPRequest *)request
{
    NSData *responseData = [request responseData];
    RssParser = [[rssParser alloc] loadXMLData:responseData];
    [self.tableView reloadData];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if ([RssParser entries] == 0) {
        return 1;
    }
    else
    {
    return [[RssParser entries]count];
    }

}

/*#define FIXED_HEIGHT_SECTION 18

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //RSSData *currentEntry = [[rssParser rssEntries] objectAtIndex:indexPath.row];

    CGSize theSize = [[currentEntry rssDescription] sizeWithFont:[UIFont systemFontOfSize:12.0f] constrainedToSize:CGSizeMake(265.0f, 9999.0f) lineBreakMode:UILineBreakModeWordWrap];
    // This gets the size of the rectangle needed to draw a multi-line string
    numberOfTextRows = round(theSize.height / 18);
    // 18 is the size of the font used in the text label
    // This will give us the number of lines in the multi-line string

    if ((indexPath.section == FIXED_HEIGHT_SECTION) || (numberOfTextRows < 2)) {
        return 44;
        // 44 is the default row height; use it for empty or one-line cells (or in other table sections)
    } else {
        return theSize.height + 35;
        // 16 seems to provide a decent space above/below; tweak to taste
    }
}*/

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    rssData *currententry =[[RssParser entries] objectAtIndex:indexPath.row];

    if ([RssParser entries] == 0) {
        cell.textLabel.text = @"No Records";
    }
    else
    {
        cell.textLabel.text = [currententry rssTitle];
    }

    return cell;
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (开发者_高级运维void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.
    /*
     <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
     [self.navigationController pushViewController:detailViewController animated:YES];
     [detailViewController release];
     */
}

@end

Any help i will be eternally grateful! :)


Did you try to profile your app with Instruments? If you use the analyzation for memory leaks properly it will directly tell you where in the code the memory leak is caused.


This line looks a bit suspect

[entries addObject:RssData];
RssData = nil;

You are nullifying the pointer but not releasing what it is pointing to. Your code is fairly hard to follow because you are not following some standard conventions.

Your init method is not safe and it should start with init... Try:

-(id)initWithXMLData:(NSData *)xml
{
    self = [super init];
    if (self) {
        entries = [[NSMutableArray alloc] init];

        xmlParser = [[NSXMLParser alloc] initWithData:xml];
        [xmlParser setDelegate:self];
        [xmlParser parse];
    }
    return self;
}

For naming things

RssData // Class names should start with uppercase
rssData // variables and ivars should start with lowercase

Otherwise it's hard to tell when you are working with a class or an instance of a class.

You should also look at using properties which would remove much of the complication of manual memory management.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜