2011-05-17 38 views
0

我已經成功創建了一個UITableView/UITableViewCell,它可以上下滑動並調整高度以顯示選項。看看這是什麼意思,我製作了一個視頻here。代碼如下:這段代碼中有沒有內存泄漏?

- (void)swipe:(UISwipeGestureRecognizer *)recognizer direction:(UISwipeGestureRecognizerDirection)direction 
{ 
    if (recognizer && recognizer.state == UIGestureRecognizerStateEnded) 
    { 
     // Get the table view cell where the swipe occured 
     CGPoint location = [recognizer locationInView:self.tableView]; 
     NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:location]; 
     MyCell* cell = (MyCell *) [self.tableView cellForRowAtIndexPath:indexPath]; 

     [self.tableView beginUpdates]; 

     //removing the options view at the other cell before adding a new one 

     if (global != nil && global.row != indexPath.row){ 
      [sideSwipeView removeFromSuperview]; 
      sideSwipeView = nil; 
     } 

     //options already exist, we need to remove it 
     if (sideSwipeView != nil){ 
      [sideSwipeView removeFromSuperview]; 
      sideSwipeView = nil; 
      slide = NO; 
     } else { 
      //options do not exist and therefore we need to add it 
      NSArray * buttonData = [[NSArray arrayWithObjects: 
            [NSDictionary dictionaryWithObjectsAndKeys:@"Mark Read", @"title", @"mark.png", @"image", nil], 
            [NSDictionary dictionaryWithObjectsAndKeys:@"Track", @"title", @"play.png", @"image", nil], 
            nil] retain]; 

      NSMutableArray * buttons = [[NSMutableArray alloc] initWithCapacity:buttonData.count]; 
      sideSwipeView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.frame.size.height-25, 320, 25)]; 
      [sideSwipeView setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin]; 
      [sideSwipeView setBackgroundColor:[UIColor colorWithPatternImage: [UIImage imageNamed:@"dotted-pattern.png"]]]; 
      [sideSwipeView setTag:-10]; 

      CGFloat leftEdge = BUTTON_LEFT_MARGIN; 
      for (NSDictionary* buttonInfo in buttonData) 
      { 
       if (!([[buttonInfo objectForKey:@"title"] isEqualToString:@"Mark Read"] && [[[topics objectAtIndex:indexPath.row] unread] intValue] == 0)) 
       { 

        UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; 

        button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; 

        UIImage* buttonImage = [UIImage imageNamed:[buttonInfo objectForKey:@"image"]]; 
        if ([[topics objectAtIndex:indexPath.row] tracked] && [[buttonInfo objectForKey:@"title"] isEqualToString:@"Track"]){ 
         buttonImage = [UIImage imageNamed:@"pause.png"]; 
         [button setSelected:YES]; 
        } else { 
         [button setSelected:NO]; 
        } 
        button.frame = CGRectMake(leftEdge, 0, buttonImage.size.width, buttonImage.size.height); 

        UIImage* grayImage = [self imageFilledWith:[UIColor colorWithWhite:0.9 alpha:1.0] using:buttonImage]; 
        [button setImage:grayImage forState:UIControlStateNormal]; 

        if ([[buttonInfo objectForKey:@"title"] isEqualToString:@"Mark Read"]){ 
         [button addTarget:self action:@selector(markRead:) forControlEvents:UIControlEventTouchUpInside]; 
        } else if ([[buttonInfo objectForKey:@"title"] isEqualToString:@"Track"]){ 
         [button addTarget:self action:@selector(track:) forControlEvents:UIControlEventTouchUpInside]; 
        } 
        [button setTag:indexPath.row]; 
        [buttons addObject:button]; 

        [sideSwipeView addSubview:button]; 

        leftEdge = leftEdge + buttonImage.size.width + BUTTON_SPACING; 
       } 
      } 

      [cell.contentView addSubview:sideSwipeView]; 
      [sideSwipeView release]; 
      global = indexPath; 
      slide = YES; 

     } 
     [self.tableView endUpdates]; 
     [self.tableView deselectRowAtIndexPath:indexPath animated:YES];   

    } 
} 

但是,我沒有信心,代碼是正確的內存(即:療法沒有內存泄漏,我不濫用任何東西)。我大多對sideSwipeView alloc,dealloc沒有把握,並將其設置爲零。我認爲其他人都很好。有人能給我任何指針嗎?

探查結果:

enter image description here

+2

在仔細研究您的代碼之前,您是否運行過分析儀?在Xcode 4中,它位於產品菜單「分析」下。在Xcode 3中,我相信它在Build菜單中是「構建和分析」。如果這是明確的,你仍然擔心,然後問這裏是有道理的,但如果你沒有運行它,我想先建議它,這樣你就可以解決它找到的任何東西。 – 2011-05-17 00:59:27

+0

我沒有運行一個探查器,圖像顯示在上面..不知道它是否與sideSwipeView有關或不像..看起來像它與按鈕有關 – aherlambang 2011-05-17 01:06:23

+0

它看起來像你需要釋放線229/234。很難準確地說出他們沒有行號的情況。 – csano 2011-05-17 01:14:27

回答

2

與Objective-C的內存管理打交道時的經驗法則是,你應該明確地釋放你的對象:(1)分配(ALLOC),(2 )克隆(複製)或新建(new,這是alloc/init的組合)。

有了這些知識,就可以查看你的代碼,找出你正在做上述事情的地方,並確保一旦你完成了它們,你就可以釋放它們。您沒有發佈的對象的一個​​示例是buttons

您還應該瞭解如何保留對象。例如,當您從超級視圖中移除一個視圖時,如果它沒有保留在其他地方,它將被釋放。您無需將值明確設置爲零。

+0

我在編寫代碼時實際上已經記住了這一點......但不知何故,我仍然不確定 – aherlambang 2011-05-17 01:03:58

+1

乍一看,它看起來並不像是在釋放按鈕數組。你也應該像他在評論中推薦的Matthew Frederick那樣進行構建和分析。如果分析儀遇到任何懷疑它沒有被釋放並會導致內存泄漏的情況,應該會產生警告。 – csano 2011-05-17 01:05:31

+1

我同意@cs,你保留buttonData數組,但它永遠不會被髮布到任何地方。如果您只打算在此範圍內使用buttonData數組,則不需要保留它。 – jjwchoy 2011-05-17 01:26:32

0

鐺靜態分析儀是很好找到簡單的泄漏,但它不會抓住他們。我發現這是值得分析你的代碼,只是看分配。在你的應用程序中執行簡單的功能,如果你看到的東西在增加,而不是像預期的那樣減少,泄漏是可能的原因。另一個指標可能是來自您預期會被釋放的類的意外錯誤和崩潰。如果您看到來自應該清除的類的消息,則調試日誌記錄也可以提取。

0
NSMutableArray * buttons = [[NSMutableArray alloc] initWithCapacity:buttonData.count]; 

好像你還沒有公佈,你在它分配的空間,這可能會導致泄漏, 使用,

[button release]; 
button=nil; 

我想,你應該檢查並確保你已經發布按鈕在以下範圍內:

else{ 
     //options do not exist and therefore we need to add it 
     NSArray * buttonData = [[NSArray arrayWithObjects: 
           [NSDictionary dictionaryWithObjectsAndKeys:@"Mark Read", @"title", @"mark.png", @"image", nil], 
           [NSDictionary dictionaryWithObjectsAndKeys:@"Track", @"title", @"play.png", @"image", nil], 
           nil] retain]; 

     NSMutableArray * buttons = [[NSMutableArray alloc] initWithCapacity:buttonData.count]; 
     sideSwipeView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.frame.size.height-25, 320, 25)]; 
     [sideSwipeView setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin]; 
     [sideSwipeView setBackgroundColor:[UIColor colorWithPatternImage: [UIImage imageNamed:@"dotted-pattern.png"]]]; 
     [sideSwipeView setTag:-10]; 

     CGFloat leftEdge = BUTTON_LEFT_MARGIN; 
     for (NSDictionary* buttonInfo in buttonData) 
     { 
      if (!([[buttonInfo objectForKey:@"title"] isEqualToString:@"Mark Read"] && [[[topics objectAtIndex:indexPath.row] unread] intValue] == 0)) 
      { 

       UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; 

       button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; 

       UIImage* buttonImage = [UIImage imageNamed:[buttonInfo objectForKey:@"image"]]; 
       if ([[topics objectAtIndex:indexPath.row] tracked] && [[buttonInfo objectForKey:@"title"] isEqualToString:@"Track"]){ 
        buttonImage = [UIImage imageNamed:@"pause.png"]; 
        [button setSelected:YES]; 
       } else { 
        [button setSelected:NO]; 
       } 
       button.frame = CGRectMake(leftEdge, 0, buttonImage.size.width, buttonImage.size.height); 

       UIImage* grayImage = [self imageFilledWith:[UIColor colorWithWhite:0.9 alpha:1.0] using:buttonImage]; 
       [button setImage:grayImage forState:UIControlStateNormal]; 

       if ([[buttonInfo objectForKey:@"title"] isEqualToString:@"Mark Read"]){ 
        [button addTarget:self action:@selector(markRead:) forControlEvents:UIControlEventTouchUpInside]; 
       } else if ([[buttonInfo objectForKey:@"title"] isEqualToString:@"Track"]){ 
        [button addTarget:self action:@selector(track:) forControlEvents:UIControlEventTouchUpInside]; 
       } 
       [button setTag:indexPath.row]; 
       [buttons addObject:button]; 

       [sideSwipeView addSubview:button]; 

       leftEdge = leftEdge + buttonImage.size.width + BUTTON_SPACING; 
      } 
     } 

     [cell.contentView addSubview:sideSwipeView]; 
     [sideSwipeView release]; 
     global = indexPath; 
     slide = YES; 

    } 
+1

您正在將釋放消息發送給nil並泄漏按鈕對象。您需要先釋放,然後將指針設置爲零。 – Hagelin 2011-05-17 06:56:44

+0

感謝您的糾正 – rptwsthi 2011-05-17 07:04:38