简体   繁体   中英

received memory warning then crash

I want to display multiple images in scrollview when images are more than 70 application will crash and display received memory error.I have get the images from document Directory

I have tried -

 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);

How can I display multiple images in scrollview?

The advice others have given to switch to a UICollectionView is good, but it has missed the real flaw in your code: the method imageNamed: of UIImage is keeping all 70 of your images in memory forever. Per the docs:

If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system's cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

Switching to this method will prevent the crashes, if you only load into memory the images that you need. UICollectionView makes this trivial, since you can only load image when the collection view asks you to fill out a cell object in its datasource's collectionView:cellForItemAtIndexpath: method.

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;
}

You are allocating and keep adding the images which causing the memory crash as all the images taking the device memory, There are many solution which build for showing the images and best is using the UICollectionView which load only the images which is showing the screen. You go for any good tutorial which can show you how to do it, here is the reference

Maybe NSCache can help you.

1 When you are displaying image at index 10.You can cache image 5-9 and 11-16 to NSCache/

2 When scrollView start Scrolling, get image from NSCache you need,and remove the object you doesn't need to display.

3 I think this can be efficient. Apple provide a demo how they handle the massive assets using caches and UICollectionView.You take a look at it.

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

I have also faced this same issue which i have resolved using below simple line.

instead of using this:

[UIImage imagedNamed:@"yourImage"];

try using this:

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

i hope it would solve your problem as by using imageWithContentsOfFile releases memory. so you won't get Memory Warning

UPDATE You may also display images from any Remote URL and also from your application's document directory using other methods of UIImage Class

do tell if it helps

You may try with UITableView . Suppose you have n number of Images then -

 - (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;

}

Use @autoreleasepool. Here are details about @autoreleaspool

The @autoreleasepool statement is doing the same job as before, instead of using the NSAutoreleasePool class. The way the NSAutoreleasePool worked was a bit weird, as creating it caused an effect throughout the whole application; @autoreleasepool creates a scoped area and makes it clearer what's within the pool and when it drains (when it goes out of scope). It's also more efficient according to Apple.

The concept of an autorelease pool is simple, whenever an object instance is marked as autoreleased (for example NSString* str = [[[NSString alloc] initWithString:@"hello"] autorelease];), it will have a retain count of +1 at that moment in time, but at the end of the run loop, the pool is drained, and any object marked autorelease then has its retain count decremented. It's a way of keeping an object around while you prepare whatever will retain it for itself.

With ARC, whilst the autorelease keyword isn't used by the developer, the underlying system that manages ARC inserts that for you. (Remember: All ARC is doing is inserting retain, release and autorelease calls for you at the appropriate times). Because of this, the existing AutoreleasePool concept needs to stay around.

If you remove the autorelease pool, your objects will start leaking For more details check here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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