App Terminated due to memory pressure - ios

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

Related

IOS CollectionView with UIImage load from url

I have an UICollectionView and I want to load picture from web to the UIImageView which on cell. (The UIImageView with tag:100 on the cell.)
The picture isn't appear when I use this method:
- (void)viewDidLoad
{
[super viewDidLoad];
Img = [NSArray arrayWithObjects:#"http://192.168.1.103:8088/Images/1.png",#"http://192.168.1.103:8088/Images/2.png",nil];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"List";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *chImage = (UIImageView *)[cell viewWithTag:100];
NSURL *imageUrl = [NSURL URLWithString:[Img objectAtIndex:indexPath.row]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
chlImage.image = image;
NSLog("%#",[Img objectAtIndex:indexPath.row]); //Here can show Img's values correctly
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"backgroung.png"]];
return cell;
}
But when I use the picture in project, it can appear correctly. like this:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"List";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *chImage = (UIImageView *)[cell viewWithTag:100];
chImage.image = [UIImages imageNames:#"123.jpg"];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"backgroung.png"]];
return cell;
}
Why it can't work when I used picture load from web? (The picture can be opened by "browser".)
Can give me some tips or correct code? Thank you very much!
You are expecting to get an UIImageView from this line:
UIImageView *chImage = (UIImageView *)[cell viewWithTag:100];
But you are not. You are getting just an UIView. So you must create an UIImageView and then use addSubview: method to add this UIImageView to the backgroudViewView.
So, it should be:
UIImageView *chImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, cell.backgroundView.frame.size.width,cell.backgroundView.frame.size.height)];
NSURL *imageUrl = [NSURL URLWithString:[Img objectAtIndex:indexPath.row]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
chImage.image = image;
NSLog("%#",[Img objectAtIndex:indexPath.row]); //Here can show Img's values correctly
[cell.backgroundView addSubview:chImage];
And finally, I have a suggestion for you. Take a look at SDWebImage library. It's an awesome feature to fetch images from URL.
Create a class ImageCell by subclassing UICollectioViewCell and create a property ImageCell.h:
#interface ImageCell : UICollectionViewCell
#property (nonatomic, strong) UIImage *dImage;
#end
Then add a function in ImageCell.m
- (void)downloadImageFromURL:(NSURL *)imageUrl
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImageView *chImageView = (UIImageView *)[cell viewWithTag:100];
chImageView.image = dImage;
});
});
}
Now from UICollectionView delegate:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"List";
ImageCell *cell = (ImageCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSURL *imageUrl = [NSURL URLWithString:[Img objectAtIndex:indexPath.row]];
[cell downloadImageFromURL:imageUrl];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
return cell;
}
And at last please make sure that you set the tag 100 to that ImageView you are trying to get. Let me know if you have any confusions.
Simply move your data fetching part from the collection view's delegate to it's viewDidLoad.
Store the images into an array. And use this as the datasource for your collection view.
ie.Each time an image gets added to the array just reload the collection view.
Or you could create a custom cell that does this as 'iOSGeek' suggested.

UICollectionView Memory Leak

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.

How to insert images in uicollectionview programmatically?

I'm pretty new to Objective-C so hopefully this all makes sense..I ran code provided in first answer Creating a UICollectionView programmatically..It is working fine .Now i want to add some pictures in cell that can expanded by mouse click .I searched many tutorial but all using nib files or storyboard files .How i can accomplish this task programmatically ?
Any help would be greatly appreciated. Thanks in advance.
as Logan suggest:
#define IMG_TAG 1000
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
cell.textLabel.text = #"test.....";
UIImage * img = [UIImage imageNamed: #"sampleImage"];
UIImageView * customImageView = (UIImageView*) [cell viewWithTag: IMG_TAG];
// two cases:
// 1) we got a "recycled" cell, so we already have an image view added
// 2) we got a "new" cell, so we must create, add image view AND TAg
// in both cases we will set image
if (customImageView){
// case 1
// nothing special
}else{
// case 2:
// add and tag:
customImageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 2, 30, 30)];
[cell addSubview: customImageView];
customImageView.tag = IMG_TAG;
}
customImageView.image = img;
return cell;
}
pls review and upvote :)
Beginner read tutroial and understand first everyting in below link and apple doc
ios-programming-uicollectionview-tutorial-with-sample-code
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionView_class/Reference/Reference.html
change this your blackground color like this approach
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipeImages objectAtIndex:indexPath.row]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
[self.view addSubview:recipeImageView];
cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:[recipeImages objectAtIndex:indexPath.row]]];
return cell;
}
output:
NOTE:
code above is WRONG!
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipeImages objectAtIndex:indexPath.row]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
[self.view addSubview:recipeImageView];
cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:[recipeImages objectAtIndex:indexPath.row]]];
return cell;
}
You allocate (better to allocate ONCE unsung TAGs...) but the code will ADD subview EVERY time cellForItemAtIndexPath is called.

Received memory warning in UICollectionView iOS 7

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

How to load images asynchronously in uitableview without memory warning?

Hi iam developing an app where i will fetch images from web service and load the images in tableview. I loaded the images asynchronously. The problem is my app get crash while scrolling the tableview and in log it shows memory recieved warning.Also same images gets repeated in many rows.Also it takes more time to load. i used the below code.
- (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];
/* UILabel * cellLabel=[[UILabel alloc] initWithFrame:CGRectMake(0, 50, cell.frame.size.width-20, 45)];
cellLabel.textColor=[UIColor blackColor];
cellLabel.backgroundColor=[UIColor clearColor];
cellLabel.tag=2;
[cell.contentView addSubview:cellLabel];*/
cell.selectionStyle=UITableViewCellSelectionStyleNone;
cell.backgroundView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"list_iPhone.png"]];
UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(10,18, 48, 48)];
imv.tag=4;
imv.image=[UIImage imageNamed:#"ImagePlaceholder.png"];
[cell.contentView addSubview:imv];
UIImageView *arrwimv = [[UIImageView alloc]initWithFrame:CGRectMake(260,35, 14, 17)];
arrwimv.image=[UIImage imageNamed:#"arrw_iPhone.png"];
[cell.contentView addSubview:arrwimv];
UILabel *descriptionLbl=[[UILabel alloc] initWithFrame:CGRectMake(100, 27, 450, 45)];
descriptionLbl.font=[UIFont CITY311_TitleFontWithSize:18];
descriptionLbl.tag=1;
descriptionLbl.textAlignment=UITextAlignmentLeft;
descriptionLbl.textColor=[UIColor blackColor];
descriptionLbl.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:descriptionLbl];
UILabel *descriptionLbl2=[[UILabel alloc] initWithFrame:CGRectMake(100, 5, 450, 45)];
descriptionLbl2.font=[UIFont CITY311_TitleFontWithSize:18];
descriptionLbl2.tag=2;
descriptionLbl2.textAlignment=UITextAlignmentLeft;
descriptionLbl2.textColor=[UIColor blackColor];
descriptionLbl2.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:descriptionLbl2];
}
UIImageView *imv2=(UIImageView *)[cell.contentView viewWithTag:4];
dispatch_async(mainQueue, ^(void) {
if(![[[issueArray objectAtIndex:indexPath.row]objectForKey:#"PhotoUrl"] isEqualToString:#""])
{
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[issueArray objectAtIndex:indexPath.row]objectForKey:#"PhotoUrl"]]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
imv2.image = image;
}
});
UILabel *lbl=(UILabel *)[cell.contentView viewWithTag:1];
lbl.text=[[issueArray objectAtIndex:indexPath.row] objectForKey:#"issueSubmittedDate"];
UILabel *lbl2=(UILabel *)[cell.contentView viewWithTag:2];
lbl2.text=[[issueArray objectAtIndex:indexPath.row] objectForKey:#"IssueName"];
return cell;
}
In view did load
mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
In .h file
dispatch_queue_t mainQueue;
Please help to load the images properly without any memory warning(Crash).Thanks in Advance.
you are reusing tableviewcells. When a cell moves off the screen, it will be set aside so that you can reuse the object. When you are doing a dequeueReusableCellWithIdentifier you can get a 'old' cell that already contains an image. If you dont' clear the data from that cell you will see the old data (image) until the new image is downloaded.
inside the if(cell==nil) you should only create the cell and set properties that will be the same for every row. Set and clear the data below that if.
The crashes probably happen because a cell can be moved out of the view and reused for an other row before the initial callback is ready. Try setting the identifier to a unique value. Something like:
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d", indexPath.Row];
Only keep your code like that when the number of rows is low. Otherwise you could get memory problems.
Instead of trying to fix it yourself, you could try using something like https://github.com/rs/SDWebImage

Resources