收到内存警告然后崩溃

时间:2015-05-26 11:10:14

标签: ios objective-c iphone crash

我想在滚动视图中显示多个图像,当图像超过70时,应用程序将崩溃并显示收到的内存错误。我从文档目录中获取图像

我试过了 -

 UIScrollView *MyScroll=[[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];

    int x=5,y=15;

    for (int i = 0; i < imgarr.count; i++)
    {
        if(x<=211)
        {

        UIImage* imagePath = [UIImage imageWithContentsOfFile:[path_array objectAtIndex:i]];

        imgView=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, 77, 75)];
        imgView.image=imagePath;

            imgeBtn=[UIButton buttonWithType:UIButtonTypeCustom];
            imgeBtn.frame=CGRectMake(x, y, 93, 110);
            [imgeBtn addTarget:self action:@selector(btnclick:) forControlEvents:UIControlEventTouchUpInside];
            imgeBtn.tag=i;
            x+=103;

        }
        else
        {
            x=5;
            y+=130;


        UIImage* imagePath = [UIImage imageWithContentsOfFile:[path_array objectAtIndex:i]];

        imgView=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, 77, 75)];
        imgView.image=imagePath;

            imgeBtn=[UIButton buttonWithType:UIButtonTypeCustom];
            imgeBtn.frame=CGRectMake(x, y, 93, 110);
            [imgeBtn addTarget:self action:@selector(btnclick:) forControlEvents:UIControlEventTouchUpInside];
            imgeBtn.tag=i;
            x+=103;

        }
        [MyScroll addSubview:imgeBtn];
        [MyScroll addSubview:imgView];
         MyScroll.contentSize=CGSizeMake(320, y+120);

如何在scrollview中显示多个图像?

7 个答案:

答案 0 :(得分:10)

其他人提出的切换到UICollectionView的建议很好,但它已经错过了代码中的真正缺陷:imageNamed:的{​​{1}}方法保留了所有70个永远记忆中的图像。根据文档:

  

如果您的图像文件只显示一次并希望显示   确保它不会被添加到系统的缓存中,你应该这样做   而是使用imageWithContentsOfFile创建您的图像:这将   可能会将您的一次性图像保留在系统图像缓存之外   改善应用的内存使用特性。

如果您只将所需的图像加载到内存中,切换到此方法可以防止崩溃。 UICollectionView使这一点变得微不足道,因为只有在集合视图要求您在其数据源的UIImage方法中填写单元格对象时才能加载图像。

答案 1 :(得分:5)

Create custom class of collection view cell 
and You can pass image name in array. 

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate>

@property (weak, nonatomic) IBOutlet UICollectionView *Collection;

@end

#import "ViewController.h"
#import "CustomCell.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.Collection registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cell"];
    [self.Collection registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellWithReuseIdentifier:@"cell"];
}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 5;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 4;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.imgview.image=[UIImage imageNamed:@"XYZ.png"];
    return cell;
}

答案 2 :(得分:2)

您正在分配并继续添加导致内存崩溃的图像,因为所有图像都占用了设备内存。有许多解决方案可用于显示图像,最好是使用UICollectionView,它只加载显示图像的图像屏幕。你可以找到任何可以告诉你如何操作的好教程,这里是reference

答案 3 :(得分:2)

也许NSCache可以帮助你。

1 当您在索引10处显示图像时。您可以将图像5-9和11-16缓存到NSCache /

2 当scrollView开始滚动时,从您需要的NSCache获取图像,并删除您不需要显示的对象。

3 我认为这可能是有效的。 Apple提供了一个演示如何使用缓存和UICollectionView处理大量资产的演示。您可以查看它。

https://developer.apple.com/library/ios/samplecode/UsingPhotosFramework/Introduction/Intro.html

答案 4 :(得分:1)

我也面临同样的问题,我已经使用下面的简单线解决了这个问题。

instead of using this:

[UIImage imagedNamed:@"yourImage"];

try using this:

[yourCell.imageview setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"yourImage" ofType:@"png"]]];

我希望通过使用imageWithContentsOfFile释放内存来解决您的问题。所以你不会得到Memory Warning

<强>更新 您还可以使用UIImage Class

的其他方法显示来自任何远程URL的图像以及应用程序的文档目录中的图像

告诉它是否有帮助

答案 5 :(得分:0)

您可以尝试使用UITableView。假设您有n个图像 -

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
        - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
        {
            // 3 is numbers of images per row
            if (n/3 *3 == n)
                return  n/3;

            return n/3 +1;
        }

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;

    }


    int x=5,y=15;

   UIImageView* imgView1=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, 93, 110)];
   imgView1.image=[UIImage imageNamed:[imgarr objectAtIndex:indexPath.row + 0]];
    x+=103;

   UIImageView* imgView2=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, 93, 110)];
    imgView2.image=[UIImage imageNamed:[imgarr objectAtIndex:indexPath.row + 1]];

    x+=103;

    UIImageView* imgView2=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, 93, 110)];
    imgView2.image=[UIImage imageNamed:[imgarr objectAtIndex:indexPath.row + 2]];


    [cell.contentView addSubview:imgView1];
     [cell.contentView addSubview:imgView2];
     [cell.contentView addSubview:imgView3];
    return cell;

}

答案 6 :(得分:0)

使用@autoreleasepool。以下是有关@autoreleaspool

的详细信息

@autoreleasepool语句正在执行与以前相同的工作,而不是使用NSAutoreleasePool类。 NSAutoreleasePool的工作方式有点奇怪,因为创建它会在整个应用程序中产生影响; @autoreleasepool创建一个范围区域,使其更清楚地知道池中的内容以及它何时消失(当它超出范围时)。根据Apple的说法,它的效率也更高。

自动释放池的概念很简单,只要对象实例被标记为自动释放(例如NSString * str = [[[NSString alloc] initWithString:@&#34; hello&#34;] autorelease];),它将在该时刻保留+1,但在运行循环结束时,池被耗尽,任何标记为自动释放的对象都会使其保留计数减少。它是一种保持物体的方式,同时准备任何可以保留物体的物体。

使用ARC,虽然开发人员不使用autorelease关键字,但管理ARC的基础系统会为您插入。 (请记住:所有ARC正在做的是在适当的时间为您插入保留,释放和自动释放呼叫)。因此,现有的AutoreleasePool概念需要保持不变。

如果删除自动释放池,则对象将开始泄漏 有关详细信息check here