I am using UICollectionView to show all the images available in my library using assets, its displaying all the images but when I scroll up and down many times , I receive a memory issue in the device and after some time it gets crashed saying CRASHED DUE TO MEMORY PRESSURE
code used are as follows
creates here the collectionview and settings its delegate
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
allPhotosCollectionView=[[UICollectionView alloc]initWithFrame:CGRectMake(5, 5, 310, 481)collectionViewLayout:layout];
[allPhotosCollectionView setDelegate:self];
[allPhotosCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[allPhotosCollectionView setDataSource:self];
[self.view addSubview:allPhotosCollectionView];
delegate methods
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return [allImageArray count];
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(95, 100);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier = #"Cell";
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
// allimageArray has the Assest URL fo the images
NSURL *aURL=[[NSURL alloc]initWithString:[NSString stringWithFormat:#"%#",[allImageArray objectAtIndex:indexPath.row]]];
[assestLibrary assetForURL:aURL resultBlock:^(ALAsset *asset)
{
UIImage *copyOfOriginalImager = [UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage] scale:0.5 orientation:UIImageOrientationUp];
UIImageView*imageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 90, 90)];
NSData *imageData;
imageData=UIImageJPEGRepresentation(copyOfOriginalImager, 0.4);
[imageView setImage:[UIImage imageWithData:imageData]];
[cell.contentView addSubview:imageView];
}
failureBlock:^(NSError *error)
{
// error handling
NSLog(#"failure-----");
}];
return cell;
}
I am facing many problems in iOS 7 , app crash due to memory pressure , please explain that too
its due to assest library. Once u fetched the image using assest libary just store it in some variable and re-use that image in
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
while scrolling the collection view it will fetch the image again and again using asset libary this will cause huge memory leak.
Edit:
UIImage *img =[imageDictionary objectForKey:imageName];
if(!img)
{
NSURL *asseturl = [NSURL URLWithString:imageName];
img = [McAssetReader readImage:asseturl];
[imageDictionary setObject:img forKey:imageName];
}
where imageDictionary is the Global Dictionay for holding the image.
imageName is the url for particular image.
There are two issues with your code:
You're keep adding imageViews to cell without even checking if one already exist, hence memory usage is growing rapidly;
You're not caching results of your image transformation and keep reading/transforming on every cell dequeue, hence you're keep pressure on disk IO and memory;
Cache and reuse technics will most likely fix your problems.
I can see issue here. Surely It will lead to memory error.
UIImageView*imageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 90, 90)];
.
.
.
[cell.contentView addSubview:imageView];
See this line. You are creating imageView everytime and holding that image into imageview.
So you can do this instead of first line.
UIImageView *imageView = [cell.contentView viewWithTag:ImageViewTag];
if (!imageView)
{
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 90, 90)];
[cell.contentView addSubview:imageView];
}
Related
My application getting crashed on iPhone4 for frequent use of 5 to 10 mins.
I having some images in application itself , have internal SQLite file, image names are stored in sqlite table and used from the name.
Also fetch some images from online DB via url (NSURL). Online DB images are loaded in UIImageView using SDWebImage framework. But still am getting "Received memory warning" and app getting terminated
I have checked with instruments its shows the image getting more data and lead to crash
getting array of images name from DB and loading image to UIImageView present in UICollectionViewCell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell1 = [self->collectionView dequeueReusableCellWithReuseIdentifier:#"cell1" forIndexPath:indexPath];
for (UIImageView *lbl in cell1.contentView.subviews)
{
if ([lbl isKindOfClass:[UIImageView class]])
{
[lbl removeFromSuperview];
}
}
imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, cell1.frame.size.width, cell1.frame.size.width)];
imgView.backgroundColor = CLEAR_COLOR;
imgView.contentMode = UIViewContentModeScaleAspectFit;
UIImage *imv = [UIImage imageNamed:(NSString *)mArray_FeatIcon[indexPath.item]];
imgView.image = imv;
[cell1.contentView addSubview:imgView];
imv = nil;
return cell1;
}
image loading from weburl in UICollectionView
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell1 = [cvGallery dequeueReusableCellWithReuseIdentifier:#"cell1" forIndexPath:indexPath];
for (UIImageView *lbl in cell1.contentView.subviews)
{
if ([lbl isKindOfClass:[UIImageView class]])
{
[lbl removeFromSuperview];
}
}
UIImageView * imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, cell1.frame.size.width, cell1.frame.size.height)];
imgView.backgroundColor = [UIColor clearColor];
NSString *urlString = [[NSString stringWithFormat:#"%#",mArrThumbUrl[indexPath.item]] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[imgView setImageWithURL:[NSURL URLWithString:urlString] placeholderImage:[UIImage imageNamed:#"logo.png"]];
[cell1.contentView addSubview:imgView];
return cell1;
}
Not able to add screen shot of instruments, because of low reputation. Thanks in advance.
May be this is due to leakage of memory management in iPhone. Please refer this tutorial link and check for NSZombies in Instruments .
Follow this link-> I think this is very useful.
http://www.raywenderlich.com/23037/how-to-use-instruments-in-xcode
I am building an application that looks like a Photo Gallery.
I follow different references, but It still not run.
The problem is with the imageView in the cell, because if I try to change the backgroundColor of the cell it works, in spite of if I try to change the image of the imageView it doesn't run.
- (void)viewDidLoad {
[super viewDidLoad];
_ownImages = [#[#"1.jpg",
#"2.jpg",
#"2.jpg",
#"3.jpg"] mutableCopy];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_photoGallery =[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[_photoGallery setDataSource:self];
[_photoGallery setDelegate:self];
[_photoGallery registerClass:[PhCell class] forCellWithReuseIdentifier:#"photoCell"];
[self.view addSubview:_photoGallery];
}
Here I change the option of the CollectionView
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _ownImages.count;
}
And finally, I create the Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PhCell *myCell = [_photoGallery dequeueReusableCellWithReuseIdentifier:#"photoCell" forIndexPath:indexPath];
long row = [indexPath row];
NSLog(#"%#", _ownImages[row]);
image = [UIImage imageNamed:_ownImages[row]];
myCell.backgroundColor = [UIColor clearColor];
myCell.imageView.image = image;
return myCell;
}
To implement the custom Cell I create an UICollectionViewCell called PhCell. In this Class I set an xib file for the cellView in which there is an imageView connected to the variable
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
in PhCell.h
The code is free of errors, but it not display the image, why?
Just try to set the imagebackground is another color, like yellow, and let see the image is shown or not.
In the line image = [UIImage imageNamed:_ownImages[row]]; I can see you have not inited the image.
Hi i am having a memory leak issue with the code bellow once my application is tested on the physical device. My problem occurs when scrolling a UiCollectioView dow but is also very slow on the load up of this view controller.
So what i am truing to do is use a NSFileManger to load images directly from the iPhones DCIM file located at this path /var/mobile/Media/DCIM/100APPLE/. After fetching these images i place them into an array and create a sort of gallery with them through the UICollectionView by populating each cell with the list of images in the array. For example cell 1 = image 1, cell 2 = image 2 and so forth. This works correctly but when scrolling crashes unexpectedly but forcefully so i am therefore assuming this is a memory leak problem. Especially when this problem does not occur on the simulator.
Here is my code:
- (void)viewDidAppear:(BOOL)animated
{
// Do any additional setup after loading the view from its nib.
path = #"/var/mobile/Media/DCIM/100APPLE/";
Images = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]mutableCopy];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
if ([[[Images objectAtIndex:indexPath.row]pathExtension] isEqualToString:#"JPG"])
{
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
static NSString *identifier = #"Cell";
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:[NSData dataWithContentsOfFile:[NSString stringWithFormat:#"%#%#", path, [Images objectAtIndex:indexPath.row]]]]];
UIView *v = [[UIView alloc]initWithFrame:CGRectMake(0, 80, cell.bounds.size.width, 20)];
v.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.4f ];
UILabel *title = [[UILabel alloc]initWithFrame:CGRectMake(0, 70, cell.bounds.size.width, 40)];
title.tag = 200;
title.text = [Images objectAtIndex:indexPath.row];
title.textColor = [UIColor whiteColor];
[cell.contentView addSubview:v];
[cell.contentView addSubview:title];
return cell;
}
else
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
static NSString *identifier = #"Cell";
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return Images.count;
}
Thanks in advance...
PS:
My app is being built as an app for jailbroken phones so please do not tell me that apple will not accept the way i am doing this.
First of all, you shouldn't assume you have a memory leak as it's pretty uncommon when using ARC; you should use instruments to test. You have a problem in that you're adding the view, v, and the label, title, to cells that already have them when you scroll, and cells are reused. This is most likely your problem. Personally, I think it's bad form to add subviews in cellForItemAtIndexPath, unless you're adding them to some cells and not others based on the indexPath. You should create a custom cell, and add the subviews in its init method (or in IB). Also, you only need to register the class once, so it shouldn't be in cellForItemAtIndexPath; a better place to put it would be viewDidLoad.
I'm new building UICollectionView and I have an issue. I would like to display images that have 300px width and calculate the right height scale. To do this, I did :
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
UIImage *image = [photos objectAtIndex:indexPath.row];
if(image){
UIImageView *imageView = [[UIImageView alloc]initWithImage:image];
float scale = (image.size.height/image.size.width)*300;
[imageView setFrame:CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, 300, scale )];
[cell addSubview:imageView];
cell.backgroundColor = [UIColor clearColor];
}else{
cell.backgroundColor = [UIColor redColor];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
UIImage *image = [photos objectAtIndex:indexPath.row];
float scale = (image.size.height/image.size.width)*300;
return CGSizeMake(300, scale);
}
This seems to work at the beginning but as soon as I scroll down, images start to overlap each others. Is that any way to avoid this ?
You have to resize cells in UICollectionView, use UICollectionViewFlowLayout
Check out the Ray Wenderlich Tutorial: http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
I need to display around 300 images on UICollectionView. I have added custom UICollectionViewCell and subview UIImageView, now when i try to display images on UICollectionView from web server it display around 150 images and then app crashes showing low level memory. Below is my code, please let me know what i am doing wrong.
-(void)updateView {
for (int i = 0; i < m_nPhotoCount; i ++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:[aryList objectAtIndex:i]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
if(image == nil)
{
NSLog(#"kashif");
}
else {
[self.imageArray addObject:image];
}
dispatch_sync(dispatch_get_main_queue(), ^{
[collectionView reloadData];
});
});
}
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return [self.imageArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"GalleryCell";
GalleryCell *cell = (GalleryCell*)[cv dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.imageView.image = [self.imageArray objectAtIndex:indexPath.row];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
return [[UICollectionReusableView alloc] init];
}
You are taking up the wrong approach. What you should do is, You should download only those number of images (equivalent to number of visible cells of CollectionView) at once.
When collection view is scrolled than download more images and purge or store previous images in the cache.
You can make use of this wonderful Image Downloading and caching library : SDWebImage
There are special libraries available for gallery. You should try library rather handling or creating collection view with large size.