【问题标题】:More Leaks On My NSXMLParser :(我的 NSXMLParser 上的更多泄漏 :(
【发布时间】:2011-10-28 19:42:51
【问题描述】:

我最终会掌握这个内存分配的想法和 iphone 开发,但我很挣扎。下面是我为 Twitter 查看器编写的 NSXMLParser 代码。它工作正常,直到代码加载大约 30 秒后才会泄漏……这让我很沮丧,因为一旦我完成了这个解析器并且没有泄漏,我就准备好了:)。

我已经观看了大量的视频教程,只是需要帮助查看我自己的代码,这样我才能得到一个想法。

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

还有 twitter 视图控制器

//
//  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

任何帮助我将永远感激! :)

【问题讨论】:

  • 在这个类的生命周期中,知道方法 loadXMLData() 被调用了多少次吗?我想知道,如果您继续分配而不释放以前的分配。虽然,我们已经发布了,但这将在 dealloc 期间进行一次发布。
  • 它在 twitterviewcontroller 中分配一次以解析我从 asihttp 请求中收到的数据。

标签: iphone objective-c ios cocoa-touch nsxmlparser


【解决方案1】:

您是否尝试使用 Instruments 来分析您的应用? 如果您正确使用内存泄漏分析,它将直接告诉您在代码中的哪个位置导致内存泄漏。

【讨论】:

  • 在xcode中我点击分析有一个问题,它就行了我分配rssParser。所以它必须在那里......但它不是很有用,因为 nsxmlparser 大约有 100 行......
【解决方案2】:

这条线看起来有点可疑

[entries addObject:RssData];
RssData = nil;

您正在使指针无效,但没有释放它所指向的内容。您的代码很难遵循,因为您没有遵循一些标准约定。

您的 init 方法不安全,它应该以 init... 开头 试试:

-(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;
}

为事物命名

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

否则很难判断您是在使用类还是类的实例。

您还应该考虑使用可以消除手动内存管理的大部分复杂性的属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-09
    • 2011-02-09
    • 2011-10-28
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 2012-02-12
    相关资源
    最近更新 更多