dealloc vs ViewDidDissapear用于内存管理

RNs*_*ost 1 iphone memory-management objective-c nsxmlparser ios

我有几个视图解析从互联网上下载的xml.

仪器泄漏工具告诉我,当我在dealloc方法中释放数据成员时我有泄漏但不是当我放入[objectname release];内部时viewDidDissapear.

这是一个主要的罪吗?

来自ac/c ++背景我发现obj-c内存管理非常混乱!

编辑:这是代码:

#import "SuggestedFriendList.h"

@implementation SuggestedFriendList

@synthesize maincell,nationalityimageview, subjectimageview, accommodationimageview;

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qualifiedName
    attributes:(NSDictionary *)attributeDict
{
    currentElement = [[elementName copy] autorelease];
    if ([elementName isEqualToString:@"shared"]) 
    { 
        tshared = [[NSMutableString alloc] init];
    }

    if ([elementName isEqualToString:@"fullname"])
    {
        tfullname = [[NSMutableString alloc] init]; 
    }

    if ([elementName isEqualToString:@"nationality"])
    {
        tnationality = [[NSMutableString alloc] init]; 
    }

    if ([elementName isEqualToString:@"subject"])
    {
        tsubject = [[NSMutableString alloc] init]; 
    }

    if ([elementName isEqualToString:@"accommodation"])
    {
        taccommodation = [[NSMutableString alloc] init]; 
    }

    if ([elementName isEqualToString:@"memberid"])
    {
        tmemberid = [[NSMutableString alloc] init]; 
    }

    if ([elementName isEqualToString:@"count"])
    {
        tcount = [[NSMutableString alloc] init]; 
    }    
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{                
    if ([currentElement isEqualToString:@"shared"])
    {            
        [tshared appendString:string];
    }

    if ([currentElement isEqualToString:@"fullname"])
    {            
        [tfullname appendString:string];
    }

    if ([currentElement isEqualToString:@"nationality"])
    {            
        [tnationality appendString:string];
    }

    if ([currentElement isEqualToString:@"subject"])
    {            
        [tsubject appendString:string];
    }

    if ([currentElement isEqualToString:@"accommodation"])
    {            
        [taccommodation appendString:string];
    }

    if ([currentElement isEqualToString:@"memberid"])
    {            
        [tmemberid appendString:string];
    }

    if ([currentElement isEqualToString:@"count"])
    {            
        [tcount appendString:string];
    }                                
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"shared"]) 
    {            
        [lshared addObject:tshared];

        [tshared release];

    }

    if ([elementName isEqualToString:@"fullname"]) 
    {            
        [lfullname addObject:tfullname];

        [tfullname release];                        
    }

    if ([elementName isEqualToString:@"nationality"]) 
    {
        [tnationality appendString:@".png"];

        [lnationality addObject:tnationality];

        [tnationality release];                        
    }

    if ([elementName isEqualToString:@"subject"]) 
    {            
        [lsubject addObject:tsubject];

        [tsubject release];                        
    }

    if ([elementName isEqualToString:@"accommodation"]) 
    {            
        [laccommodation addObject:taccommodation];

        [taccommodation release];                        
    }

    if ([elementName isEqualToString:@"memberid"]) 
    {            
        [lmemberid addObject:tmemberid];

        [tmemberid release];                        
    }

    if ([elementName isEqualToString:@"count"]) 
    {            
        count = [[NSMutableString alloc] init];

        count = tcount;

        [tcount release];                        
    }                        
}    

-(void)fetchsuggestions
{        
    MyManager *sharedManager = [MyManager sharedManager];

    suggestiondetailxml = [[NSMutableData alloc] init];

    NSString *urlString = [NSString stringWithFormat:@"http://secreturl.com/a.php?username=%@&password=%@",sharedManager.user,sharedManager.passw];

    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];                
}

-(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
    [suggestiondetailxml appendData:data];
}

-(void) connectionDidFinishLoading:(NSURLConnection *)conn
{
    NSString *xmlcheck = [[[NSString alloc] initWithData:suggestiondetailxml encoding:NSUTF8StringEncoding] autorelease];

    NSLog(@"%@",xmlcheck);

    lshared = [[NSMutableArray alloc] init];        
    lfullname = [[NSMutableArray alloc] init];        
    lnationality = [[NSMutableArray alloc] init];
    lsubject = [[NSMutableArray alloc] init];
    laccommodation = [[NSMutableArray alloc] init];
    lmemberid = [[NSMutableArray alloc] init];

    NSXMLParser *parser = [[NSXMLParser alloc] initWithData: suggestiondetailxml];        
    [parser setDelegate:self];        
    [parser parse];        
    [parser release];

    //[xmlcheck release]; //causes crash

    [connection release];
    connection = nil;

    [suggestiondetailxml release];

    [[self tableView] reloadData];
    NSLog(@"%@",lmemberid);                
}

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

- (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
{
    [super viewDidLoad];        
    [[self navigationItem] setTitle:@"My Culture"];

    // 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)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

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

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

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [lshared release];
    [lfullname release];
    [lnationality release];
    [lsubject release];
    [laccommodation release];
     [lmemberid release];
    //[count release];                
}

- (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
{        
    return [lfullname count];
}


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 93.0;
}        

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
    if (cell==nil) 
    {
        [[NSBundle mainBundle] loadNibNamed:@"SuggestedFriendCell" owner:self options:nil];            
        cell = maincell;             
        //self.detailcell = nil;
    }        
    UILabel *name;
    name = (UILabel *)[cell viewWithTag:4];        
    name.text=[lfullname objectAtIndex:indexPath.row];

    if(([[lshared objectAtIndex:indexPath.row]isEqualToString:@"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"nationalityandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"nationalityandsubject"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"nationality"]))
    {            
        UIImageView *nationality;
        nationality = (UIImageView *)[cell viewWithTag:1];

        nationality.image=[UIImage imageNamed:[lnationality objectAtIndex:indexPath.row]]; 
    }        

    if(([[lshared objectAtIndex:indexPath.row]isEqualToString:@"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"nationalityandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"subjectandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"accommodation"]))
    {
        UIImageView *accommodation;            
        accommodation = (UIImageView *)[cell viewWithTag:2];            
        accommodation.image=[UIImage imageNamed:@"accommodation.jpeg"];
    }

    if(([[lshared objectAtIndex:indexPath.row]isEqualToString:@"all"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"nationalityandsubject"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"subjectandaccommodation"])||([[lshared objectAtIndex:indexPath.row]isEqualToString:@"subject"]))
    {            
        UIImageView *subject;
        subject = (UIImageView *)[cell viewWithTag:3];            
        subject.image=[UIImage imageNamed:@"degree.jpg"];                        
    }                                
    return cell;
}

#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];
     */

    MyManager *sharedManager = [MyManager sharedManager];

    int row = indexPath.row;

    sharedManager.interrogatedmemberid=[lmemberid objectAtIndex:row];

    ViewFriendProfile *frienddetail_vc = [[[ViewFriendProfile alloc] init] autorelease];

    [[self navigationController] pushViewController:frienddetail_vc animated:YES];


}

-(void)dealloc
{





    [super dealloc];

}

@end
Run Code Online (Sandbox Code Playgroud)

当我取消注释[tcount release]时,它会导致崩溃:为什么会这样.

PS:我很抱歉格式化:如何复制和粘贴代码,使其出现在代码块中?

谢谢

Sid*_*Sid 8

要了解正在发生的事情,您需要了解viewWillAppear和viewWillDis似乎如何工作.

在视图控制器的生命周期中,这两种方法都会被多次调用,具体取决于您是按下/弹出一个视图控制器,还是从视图控制器中显示/取消一个模态.

例如:

  1. 推动viewController A:在viewController A上调用viewDidLoad和viewWillAppear
  2. 从viewController推送viewController B:在viewController A上调用viewWillDisappear,在viewController B上调用viewDidLoad和viewWillAppear
  3. 流行的viewController B到回去的viewController答:viewWillDisappear上的viewController b调用它,viewDidUnload呼吁的viewController B,dealloc中呼吁的viewController B,viewWillAppear中呼吁一个的viewController
  4. 从viewController A显示模态A:在viewController A上调用viewWillDisappear
  5. 在viewController A上调用模态:viewWillAppear
  6. Pop viewController A:在viewController A上调用viewWillDisappear,在viewController A上调用viewDidUnload,在viewController A上调用dealloc

听起来像是在viewWillAppear中分配一个对象,它被多次调用,但是在dealloc方法中释放它,只调用一次,因此内存泄漏.

在viewWillDisappear中释放对象是在viewWillAppear中平衡分配,因此没有泄漏.

我现在只能说,除非你有充分的理由在viewWillAppear中分配一些东西(也就是说,你知道你在做什么),不要这样做.

我可以告诉你更多的内容...为你想要做的事情发布更多代码可能会帮助你得到更详细的答案:)

希望这会有所帮助.


代码发布后编辑.

首先,你的意思是"当我取消注释[ 计数释放]"时?你可以发布该崩溃的控制台消息吗?它崩溃了,因为parserDidEndElement是它分配的地方,但是它已经在viewWillDisappear中发布了.如果这些没有平衡,您将获得EXC_BAD_ACCESS

来你的记忆情况.我现在看到为什么在viewWillDisappear中释放修复了泄漏.您正在调用fetchsuggestionsviewWillAppear,而viewWillAppear又会创建并触发URL请求.这将导致connectionDidFinishLoading成功连接被调用.这是您分配各种ivars的地方.由于我之前提到过viewWillAppear被多次调用,这意味着你多次触发连接会导致connectionDidFinishLoading被多次调用.

这就是为什么释放viewWillDisappear修复泄漏的原因,因为对于a上的每个分配viewWillAppear,你通过释放来平衡它viewWillDisappear.

你错过的是你的程序会在没有可用的网络时崩溃.这是因为connectionDidFinishLoading当没有网络时不会被调用.现在,当您尝试发布时viewWillDisappear,您将获得一个EXC_BAD_ACCESS,因为您尝试释放之前从未分配过的已释放的实例viewWillAppear.

我不认为我需要fetchsuggestions在viewWillAppear上多次调用,除非你是故意这样做的.

这是我现在看到的最明显的事情......问题可能(并且可能是)多重,但我们如何从重构代码开始,记住viewWillAppear/Disappear中的多个不平衡的alloc和release可能不是一个好主意...?:)