2011-11-02 51 views
1

我有幾個解析從互聯網上下載的XML視圖。dealloc vs ViewDidDissapear的內存管理

儀器泄漏工具告訴我,當我在dealloc方法中釋放數據成員時發生泄漏,但當我將[objectname release];放入viewDidDissapear時,泄漏沒有。

這是一個基本的罪?

來自c/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 

當我取消[TCOUNT發行]它會導致崩潰:這是爲什麼。

PS:我很抱歉格式化:如何複製和粘貼代碼,使其出現在代碼塊中?

感謝

回答

8

要了解發生了什麼事情,你需要了解如何viewWillAppear中和viewWillDisappear工作。

這兩種方法在視圖控制器的生命週期中都會被調用多次,具體取決於您是在推/拉視圖控制器,還是在顯示/解除視圖控制器中的模態。

例如:

  1. 推送的viewController答:viewDidLoad中和viewWillAppear中稱爲上的viewController甲
  2. 推送的viewController從的viewController A B:viewWillDisappear上的viewController甲調用,viewDidLoad中和viewWillAppear中稱爲上的viewController乙
  3. pop viewController B返回viewController A:viewWillDisappear調用viewController B,viewDidUnload調用viewController B,dealloc調用viewController B,viewWillAppear調用viewController A
  4. 顯示來自的viewController A中的模態:viewWillDisappear稱爲上的viewController甲
  5. 關閉該模態:viewWillAppear中稱爲上的viewController甲
  6. 流行的viewController答:viewWillDisappear稱爲上的viewController A,viewDidUnload上的viewController甲叫,的dealloc稱爲上的viewController甲

聽起來你分配在viewWillAppear中,這是多次調用對象,但重新分配它在dealloc方法,這就是所謂只有一次,因此內存泄漏

釋放你的對象在viewWillDisappear是平衡viewWillAppear的分配,因此沒有泄漏。

在這一點上我只能說,除非你有很好的理由在viewWillAppear中分配一些東西(即你知道你在做什麼),否則不要這樣做。

我可以告訴你沒有更多...發佈更多的代碼爲你想做什麼可能會幫助你得到一個更詳細的答案:)

希望這有助於雖然。


編輯代碼公佈後。

首先,你的意思是'當我取消註釋[計數發佈]'?你能發佈那個崩潰的控制檯消息嗎?它崩潰了,因爲parserDidEndElement是它被分配的地方,但它正在viewWillDisappear中發佈。如果這些不平衡,你會得到一個EXC_BAD_ACCESS

來到你的記憶狀況。我現在看到爲什麼釋放viewWillDisappear修復泄漏。您在viewWillAppear上調用fetchsuggestions,然後創建並觸發URL請求。這將導致connectionDidFinishLoading被成功連接調用。這裏是你分配各種ivars的地方。由於我之前提到viewWillAppear被多次調用,這意味着您多次觸發連接,導致多次調用connectionDidFinishLoading

這就是爲什麼在viewWillDisappear中發佈修復泄漏的原因,因爲對於viewWillAppear上的每個分配,您通過在viewWillDisappear中發佈來平衡它。

雖然你錯過了什麼,就是當沒有網絡可用時,你的程序會崩潰。這是因爲當沒有網絡時,connectionDidFinishLoading不會被調用。現在,當您嘗試在viewWillDisappear中發佈時,您將獲得EXC_BAD_ACCESS,因爲您試圖釋放之前從未在viewWillAppear中再次分配的釋放實例。

我認爲我不認爲我需要多次在viewWillAppear上調用fetchsuggestions,除非您有意這樣做。

這是我目前看到的最明顯的事情......問題可能是(也可能是多個),但是我們如何通過重構代碼開始,同時牢記在viewWillAppear中的多個不平衡的分配和釋放/消失可能不是一個好主意......? :)

+0

查看didDissapear適合在哪裏? –

+0

就像它在答案中解釋的那樣,你可以看看viewWillAppear和viewWillDisappear並行。這就是爲什麼我覺得你的泄漏在viewWillDisappear釋放期間被解決,因爲我認爲你是在viewWillAppear中分配對象。我現在所能提供的只是教育投機。如果您發佈代碼並詳細說明您的問題,我將能夠更好地解釋它。 – Sid

+0

Hey Sid;感謝你的幫助......代碼在上面的問題中。 –

0

我發現有助於發現潛在內存泄漏的工具是Build> Analyze in Xcode。

它告訴你哪一行做了分配,以及它在哪裏泄漏代碼。它還會告訴你你在哪裏做出了不正確的[對象釋放]遞減計數。

0

有一種可能性,你沒有完全釋放視圖,dealloc永遠不會被調用。

1

在viewWillDisappear中發佈任何東西都很奇怪,但是如果你在viewWillAppear中分配它,這是正確的。我認爲你應該在viewDidLoad中分配你的對象,並在viewDidUnload中釋放它們。在某些情況下會避免不必要的重新創建它們。

你應該釋放保留伊娃在dealloc。只要確保當你用其他方法釋放它們時,你將它們設置爲零,所以如果它們再次釋放,它只是將釋放發送到零,這是一個無操作。

+0

我希望如果Sid的生命週期描述完成,我將在顯示的視圖之間改變內容,而不是加載視圖 –