繁体   English   中英

滚动UIScrollView时发生内存泄漏

[英]Memory leak when scrolling UIScrollView

在我的iPhone应用程序中,我正在动态添加UIScrollView并将n个UIImageUIButton添加到scrollview中。 在这里,图像是从不同的URL加载的,而按钮标题则来自SQlite数据库。 一切顺利。 但是,当我滚动滚动视图时,现在我收到内存警告,级别为1,一段时间后,级别为2,并导致应用程序崩溃。 我正在使用ARC。 我该如何解决这个问题?

- (void)setUpViewLayout{
    int newContentSize = [appDelegate.itemArray count] * 125;

    menuItemIdArray = [[NSMutableArray alloc]init];
    mainView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 100, 480, 220)];
    mainView.contentSize = CGSizeMake(newContentSize, 220);
    mainView.tag = 100;
    mainView.delegate = self;
    mainView.userInteractionEnabled = YES;
    mainView.backgroundColor = [UIColor clearColor];

    int xPosition = 20;

    for (tagVal = 0; tagVal < [appDelegate.itemArray count]; tagVal++) {
        [self createImage:xPosition];
        [self createButton];
        xPosition = xPosition + 120;
    }
    [self.view addSubview:mainView];
}

- (void)createImage:(int)xPosition{
    DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:tagVal];

    NSString *url = [NSString stringWithFormat:@"%@",itemObj.notAvialableIcon];
    imgView = [[UIImageView alloc]initWithFrame:CGRectMake(xPosition+8, 48, 110, 123)];
    imgView.userInteractionEnabled = YES;
    imgView.tag = tagVal;

    [imgView setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"item01.png"]];

    [mainView addSubview:imgView];
}
- (void)createButton{
    DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:tagVal];
    button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(5, 90, 100, 26);
    button.tag = tagVal;
    button.userInteractionEnabled = YES;
    button.tag = tagVal;
    button.titleLabel.textColor = [UIColor blueColor];
    button.titleLabel.font = [UIFont systemFontOfSize:9.0];
    NSString *name = [NSString stringWithFormat:@"%@",itemObj.itemStatus];
    itmName = [NSString stringWithFormat:@"%@",itemObj.itemName];

    NSString *date = [self changeDateFormat:itemObj.itemReleaseDate];          
    [button setTitle:date forState:UIControlStateNormal]; 
    button.userInteractionEnabled = NO;
    button setBackgroundImage:[UIImage imageNamed:@"not_available_bttn_bck_img"] forState:UIControlStateNormal];

    [imgView addSubview:button];
}
  1. 不要一次将所有子视图添加到滚动视图中。 那太贵了。

  2. 当滚动视图滚动时,获取滚动视图的可见矩形,然后添加图像和按钮,使其恰好位于该矩形的范围内或更多。

  3. 当可见子视图不可见时,从超级视图中删除。

您需要确定代码的哪一部分会导致泄漏。 您可以通过几种方法执行此操作。

一种方法是在xcode中使用内置的分析器。 它分析您的代码并检测(某些)潜在的内存泄漏。

仪器工具也是查找这些泄漏的好工具。 使用分配/泄漏组件启动它。 转到您的滚动视图,并在滚动视图后做一个示例。 您的泄漏应该显示出来。 现在,您可以查找泄漏并让仪器直接在代码中找到正确的位置。

第三种选择是遍历您的代码,并尝试弄清楚自己正在发生什么。 了解内存管理是ios设备编程的重要组成部分。

在这里在您的滚动视图中发布您正在使用的代码怎么样,以便我们看一下?

Abhishek绝对正确,所有子视图都必须在添加到超级视图后释放。 那会导致泄漏。 具体来说,一旦滚动视图离开屏幕并被释放,其子视图将不会按原样释放。 从分配开始,它们的保留计数仍为1。

但是,只要滚动视图仍在屏幕上,就不会泄漏。 超级视图会保留其所有子视图(即,将其保留计数增加1)。如果子视图已分配但未释放,则其保留计数为2。如果已分配并释放了子视图,则其保留计数为1。只要滚动视图存在,其子视图仍将正确保留。

如果在滚动视图仍处于启动状态时收到内存警告,则问题可能不在于泄漏,而可能是内存过度使用。 如果继续将图像添加到较大的滚动视图,则肯定会遇到内存过剩的问题。

为了用图像填充较大的滚动视图,但又避免内存过多,您可以查看ScrollViewSuite演示的第三个示例,即平铺。 这对您应该很好,因为您的图像和按钮的大小相同,并且可以充当图块。

这个想法是从滚动视图中创建一种表格视图,现在可以回收图像切片而不是单元格。 滚动视图是子类的,并且一组可重复使用的磁贴保留为其实例变量之一。 实现的关键是在layoutSubviews中,从超级视图中删除已移出可见区域的图块,然后回收图块以获取新的可见内容并将其添加为子视图。 这样,只有可见的图块被加载到内存中。 而且,它可以回收图块,就像表格视图可以回收单元格一样。

从滚动视图的大小来看,除了平铺和回收利用之外,您别无选择。 尽管如此,这是一个不错的选择。

更新:李五宝本质上总结了需要做的事情。 ScrollViewSuite演示向您展示了如何。

我正在对此做出新的回应。 这是我们所有人都错过的简单解决方案。

从您发布的代码来看,这只是侧面的表格视图。 因此,您不必构建自己的平铺滚动视图。

这里有一些代码可以帮助您入门。 设置表格视图时,将其旋转90度,设置行高并消除分隔线:

tableView.transform = CGAffineTransformMakeRotation(0.5 * M_PI);
tableView.rowHeight = 120.0;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

您必须设置表格视图的框架,以便旋转后它处于正确的位置。 本质上,它与当前滚动视图的框架或该框架在其侧面相同。

这是表视图的几个数据源方法:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [appDelegate.itemArray count];
}

表格单元可以是非常简单的自定义表格单元,它们只有一个图像视图和该图像视图上的一个按钮。 您也可以旋转图像视图,以便正确显示图像,而不是在侧面显示图像。 或者,您可以在加载照片之前在照片编辑器或图像编辑器中旋转所有图像。

就是这样。 与往常一样,表视图将负责回收单元并优化内存使用。

//you had allocated the things but did not release it ... it was the reason of leak


- (void)setUpViewLayout{
int newContentSize = [appDelegate.itemArray count] * 125;

// menuItemIdArray = [[NSMutableArray alloc]init]; why you are allocating this array

UIScrollView *mainView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 100, 480, 220)];
mainView.contentSize = CGSizeMake(newContentSize, 220);
mainView.tag = 100;
mainView.delegate = self;
mainView.userInteractionEnabled = YES;
mainView.backgroundColor = [UIColor clearColor];

int xPosition = 20;

for (tagVal = 0; tagVal < [appDelegate.itemArray count]; tagVal++) {
    [self createImage:xPosition];
    [self createButton];
    xPosition = xPosition + 120;
}
[self.view addSubview:mainView];
[mainView relese];//release scroll view here
}

- (void)createImage:(int)xPosition{
DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:tagVal];

NSString *url = [NSString stringWithFormat:@"%@",itemObj.notAvialableIcon];
imgView = [[UIImageView alloc]initWithFrame:CGRectMake(xPosition+8, 48, 110, 123)];
imgView.userInteractionEnabled = YES;
imgView.tag = tagVal;

   [imgView setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage  imageNamed:@"item01.png"]];

   [mainView addSubview:imgView];
   [imgView release]; //release imageview here
}
 - (void)createButton{
DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:tagVal];
button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(5, 90, 100, 26);
button.tag = tagVal;
button.userInteractionEnabled = YES;
button.tag = tagVal;
button.titleLabel.textColor = [UIColor blueColor];
button.titleLabel.font = [UIFont systemFontOfSize:9.0];
NSString *name = [NSString stringWithFormat:@"%@",itemObj.itemStatus];
itmName = [NSString stringWithFormat:@"%@",itemObj.itemName];

NSString *date = [self changeDateFormat:itemObj.itemReleaseDate];          
[button setTitle:date forState:UIControlStateNormal]; 
button.userInteractionEnabled = NO;
button setBackgroundImage:[UIImage imageNamed:@"not_available_bttn_bck_img"] forState:UIControlStateNormal];

[imgView addSubview:button];
}

可以帮你吗

这里有3条建议给您:

这是苹果的错误。 UIScrollView甚至会泄漏以下代码:

UIScrollView *s = [[UIScrollView alloc] initWithFrame:self.view.bounds];
s.contentSize = CGSizeMake(320, 800);
[self.view addSubview:s];
[s release];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM