这段代码中有没有内存泄漏?

时间:2011-05-17 00:44:33

标签: iphone objective-c memory

我已成功创建了一个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以及将其设置为nil大多没有信心。我认为其他人都很好。有人可以给我任何指示吗?

Profiler结果:

enter image description here

3 个答案:

答案 0 :(得分:2)

在Objective-C中处理内存管理时的经验法则是,您应该显式释放您的对象:(1)分配(alloc),(2)克隆(复制)或newing up(new,是alloc / init的组合。

有了这些知识,请查看您的代码,查找您正在执行上述操作的位置,并确保在完成这些操作后释放它们。您未发布的对象的一个​​示例是buttons

您还应该了解如何保留对象。例如,当您从超级视图中删除视图时,如果它未在其他任何地方保留,则会被释放。您不需要将值显式设置为nil。

答案 1 :(得分:0)

铿锵静态分析仪很适合发现简单的泄漏,但它不能完全捕获它们。我发现值得分析你的代码并只是看分配。在您的应用程序中执行简单的功能,如果您看到事情增加,而不是按预期减少,则可能是泄漏。另一个指标可能是意外错误和崩溃,这些错误来自您希望已取消分配的类。如果您看到来自应该已清除的类的消息,则调试日志记录也可以选择。

答案 2 :(得分: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;

    }