收到内存警告然后崩溃

Posted

技术标签:

【中文标题】收到内存警告然后崩溃【英文标题】:received memory warning then crash 【发布时间】:2015-08-08 00:40:45 【问题描述】:

我想在滚动视图中显示多个图像,当图像超过 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);

如何在滚动视图中显示多张图片?

【问题讨论】:

您能解释一下为什么要使用 if(x Scrollview 并不是显示多个图像的更好方法。 UICollectionView 是显示图像的更好方法,因为它可重用。每次在 Scrollview 中分配内存时,应用程序都会崩溃或负载过大。 我尝试了 UIScrollView 和 UICollectionView 但结果是一样的。 使用 uicollection 视图代替 uiscroll 视图会更好,因为在 uicollection 视图中我们能够创建一个可重用的单元格。 @sohil 请以更好的方式消耗你的赏金,你现在正在消耗宽限期 【参考方案1】:

其他人给出的切换到UICollectionView 的建议很好,但它忽略了代码中的真正缺陷:UIImage 的方法imageNamed: 将所有 70 个图像永久保存在内存中。根据文档:

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

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

【讨论】:

【参考方案2】:
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;

【讨论】:

【参考方案3】:

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

【讨论】:

对不起,它不起作用我使用 UIColllectionView , UITabelview 和 Scollview 都是相同的结果。我已经从文档目录中获取图像【参考方案4】:

也许 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

【讨论】:

【参考方案5】:

我也遇到了同样的问题,我用下面的简单线解决了这个问题。

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 以及应用程序文档目录的图像

告诉它是否有帮助

【讨论】:

UIImage imageWithContentsOfFile:] 确实会消耗内存——只是它不会是永久性的。此外,仅仅因为您可以使用此方法从任何 URL 获取图像并不意味着您应该;此方法是同步的,因此在这种情况下绝不应从主线程调用。 是的,这就是问卷有问题的原因。此内存将被释放。其次,使用 URL 取决于问卷逻辑。它只是一个选项伙伴。还有一件事。您是否刚刚投反对票并对此发表评论以证明您投反对票的合理性? 您说的是“不消耗内存”,而不是“释放后不会留在内存中”。有很大的不同。至于“远程 URL”这件事,如果您不关心软件的质量,它只是一个选项。 Apple 关于类似方法的文档 ([NSData dataWithContentsOfURL:])明确说不要这样做。 你不能只编辑我的答案而不是投反对票吗...?【参考方案6】:

你可以试试 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;


【讨论】:

你试过返回什么“[imgarr objectAtIndex:indexPath.row + 0]”。我认为它显示重复的图像。【参考方案7】:

使用@autoreleasepool。以下是有关@autorelaspool 的详细信息

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

自动释放池的概念很简单,只要一个对象实例被标记为自动释放(例如 NSString* str = [[[NSString alloc] initWithString:@"hello"] autorelease];),它就会有一个retain在那个时刻计数 +1,但在运行循环结束时,池被耗尽,任何标记为 autorelease 的对象的保留计数都会减少。这是一种在您准备任何可以为自己保留的东西时保留对象的方法。

使用 ARC,虽然开发人员不使用 autorelease 关键字,但管理 ARC 的底层系统会为您插入该关键字。 (请记住:ARC 所做的只是在适当的时候为您插入保留、释放和自动释放调用)。因此,现有的 AutoreleasePool 概念需要保留。

如果您删除自动释放池,您的对象将开始泄漏 更多详情check here

【讨论】:

以上是关于收到内存警告然后崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在 UITesting 期间导致内存警告和崩溃的背景图像

UIImage 导致我的应用程序崩溃:收到内存警告

AVAssetWriter 内存错误

应用程序收到内存不足警告但只有 5.7MB 的活动字节

NSuncaughtexceptionhandler 没有捕获内存警告崩溃

在 UICollectionView iOS 7 中收到内存警告