My iPhone App displays a CollectionView with about 100 Images separated by Headers. The Images have a size from about 200Kb. In the debug navigator the memory increases up to 1.75 GB while scrolling the CollectionView. It still runs smooth, but there must be a reason for that.
#property (strong, nonatomic) NSArray *picturesMoon;
#property (strong, nonatomic) NSArray *picturesEarth;
#property (strong, nonatomic) NSArray *picturesVenus;
#property (strong, nonatomic) NSArray *picturesMars;
#property (strong, nonatomic) NSDictionary *plistDict;
#property (strong, nonatomic) NSString *picName;
#property (strong, nonatomic) MyCustomCell *myCell;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Milkyway.png"]];
self.plistDict=[[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Praxis" ofType:#"plist"]] objectForKey:#"Universe"];
// Pictures Moon
picturesMoon = [self.plistDict objectForKey:#"Moon"];
// Pictures Earth
picturesEarth = [self.plistDict objectForKey:#"Earth"];
// Pictures Mars
picturesMars = [self.plistDict objectForKey:#"Mars"];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
self.myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"collectionCell" forIndexPath:indexPath];
// Sections
switch (indexPath.section) {
case 0:
self.myCell.imageInCell.image = [UIImage imageNamed:[picturesMoon objectAtIndex:indexPath.item]];
break;
case 1:
self.myCell.imageInCell.image = [UIImage imageNamed:[picturesEarth objectAtIndex:indexPath.item]];
break;
case 2:
self.myCell.imageInCell.image = [UIImage imageNamed:[picturesMars objectAtIndex:indexPath.item]];
break;
case 3:
self.myCell.imageInCell.image = [UIImage imageNamed:[picturesVenus objectAtIndex:indexPath.item]];
break;
default:
break;
}
return self.myCell
}
- (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
// Header for Sections
HeaderCollectionView *myHeaderView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"Header" forIndexPath:indexPath];
switch (indexPath.section) {
case 0:
myHeaderView.labelOutlet.text = #"Moon";
break;
case 1:
myHeaderView.labelOutlet.text = #"Earth";
break;
...
...
default:
break
}
return myHeaderView;
}
MyCustomCell is just a few line of Code
#import "MyCustomCell.h"
#implementation MyCustomCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
and the Header for MyCustomCell just
#import <UIKit/UIKit.h>
#interface MyCustomCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet UIImageView *imageInCell;
#end
[UIImage imageNamed:] caches the images. The large memory footprint isn't necessarily a problem, as the cache will be automatically purged if memory is too low. That said, if you want to avoid caching, you can use another method to load the images, for example:
NSString *imageName = [picturesMars objectAtIndex:indexPath.item];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:#"PNG"]; // PNG, or whatever file tile you are actually using
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
self.myCell.imageInCell.image = image;
Related
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
[_keyboard.collectionView registerClass:[NibCell class] forCellWithReuseIdentifier:#"Cell"];
static NSString *identifier = #"Cell";
NibCell *cell = [self.keyboard.collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView * rampageGifImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, cell.frame.size.width, cell.frame.size.height)];
[rampageGifImage setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#.gif",[rampageGif objectAtIndex:indexPath.row]]]];
[cell.layer setCornerRadius:4];
[cell addSubview:rampageGifImage];
return cell;
}
You can use Gif Image by Adding SDWebImage from Github in your project.
Try like this,
#import "UIImage+GIF.h"
_imageViewAnimatedGif.image= [UIImage sd_animatedGIFNamed:#"YOURGIF_IMAGE"];
Hope this will help you.
Try it. It is small category that could loads animated GIF. Also, jpg, png, etc..
#import "ViewController.h"
#import "UIImage+Gif.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIImageView *imageView1;
#property (weak, nonatomic) IBOutlet UIImageView *imageView2;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Usage 1 : gifWidthData
NSData *data = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"f1" withExtension:#"gif"]];
self.imageView1.image = [UIImage gifWithData:data];
// Usage 2 : gifWidthURL
NSURL *url = [[NSBundle mainBundle] URLForResource:#"f2" withExtension:#"gif"];
self.imageView2.image = [UIImage gifWithURL:url];
}
I have a memory leak which crashes the app. When i comment line above, i don't have any memory leak.
myCell.image1.image = image;
myCell is a custom UICollectionViewCell and created as:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCollectionCell *myCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"project" forIndexPath:indexPath];
NSData *imageData = [NSData dataWithContentsOfFile:_images[row] options:0 error:NULL];
UIImage *image = [UIImage imageWithData:imageData];
myCell.image1.image = image;
return myCell;
}
The image is about 8 MB and there are 7 images. When I open the view controller for the forth time, the app crashes (8x7x4 > 200 MB) ;)
CustomCollectionCell.h
#import <UIKit/UIKit.h>
#import "CellButton.h"
#interface CustomCollectionCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet UILabel *titlePro;
#property (strong, nonatomic) IBOutlet UILabel *datePro;
#property (strong, nonatomic) IBOutlet UIImageView *image1;
#property (strong, nonatomic) IBOutlet CellButton * button;
#end
CustomCollectionCell.m
#import "CustomCollectionCell.h"
#import "UIView+Themes.h"
#implementation CustomCollectionCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
#end
I profiled and Live Bytes get higher than 200 MB, and the app crashes without errors. When i comment the myCell.image1.image = image;. The app doesn't crash.
I'm using ARC.
Do you have any ideas?
The view controller that contains CustomCollectionCell had a modal segue and i never called the line below.
[self dismissViewControllerAnimated:YES completion:nil];
That was why my images were not released.
To preface, I have some experience with iOS development, but this is my first app that I am going to publish to the AppStore, and also my first experience utilizing UICollectionView.
Here is a summary of what I am doing in my app:
I have a paged UICollectionView which contains several fullscreen UICollectionViewCells. Within each of these cells is another UICollectionView ('subCollectionView'), containing UICollectionViewCells ('subCollectionViewCells') which currently have their label set to "Test Text". When scrolling to the second collectionViewCell, the subCollectionViewCells of the first collectionViewCell are visible behind the second collectionViewCell's subCollectionView. I have linked the images to what is happening here.
The CollectionViewCell that includes the subCollectionView:
[VLCategoryCollectionViewCell.h]
#import <UIKit/UIKit.h>
#interface VLCategoryCollectionViewCell : UICollectionViewCell
#property (nonatomic, strong) NSString *imageName;
#property (strong, nonatomic) IBOutlet UIView *moduleSubview;
- (void)updateCell;
#end
[VLCategoryCollectionViewCell.m]
#import "VLCategoryCollectionViewCell.h"
#import "VLModuleViewController.h"
#interface VLCategoryCollectionViewCell()
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
#property (strong, nonatomic) IBOutlet UILabel *categoryName;
#property (strong, nonatomic) VLModuleViewController *moduleViewController;
#end
#implementation VLCategoryCollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *arrayOfViews = [[NSBundle mainBundle]
loadNibNamed:#"VLCategoryCollectionViewCell" owner:self options:nil];
if ([arrayOfViews count] < 1) {
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
-(void)updateCell {
_moduleViewController = [[VLModuleViewController alloc] initWithNibName:#"VLModuleViewController" bundle:nil];
_moduleViewController.view.frame = self.moduleSubview.bounds;
[self.moduleSubview addSubview:_moduleViewController.view];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Assets"];
NSString *filename = [NSString stringWithFormat:#"%#/%#", sourcePath, self.imageName];
UIImage *image = [UIImage imageWithContentsOfFile:filename];
NSString *fileTitle = [[filename lastPathComponent] stringByDeletingPathExtension];
[self.categoryName setFont:[UIFont fontWithName:#"OpenSans-ExtraBold" size:72.0]];
[self.categoryName setText:fileTitle];
[self.imageView setImage:image];
[self.imageView setContentMode:UIViewContentModeScaleAspectFit];
}
#end
[VLModuleViewController.h]
#import <UIKit/UIKit.h>
#interface VLModuleViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
#end
[VLModuleViewController.m]
#import "VLModuleViewController.h"
#import "VLModuleCollectionViewCell.h"
#interface VLModuleViewController ()
#property (nonatomic, strong) IBOutlet UICollectionView *moduleView;
#property (nonatomic, strong) NSArray *moduleArray;
#property (nonatomic) int currentIndex;
#property (nonatomic) NSString *cellIdentifier;
#end
#implementation VLModuleViewController
- (void)loadView {
[super loadView];
NSArray *moduleArray = [[NSBundle mainBundle] pathsForResourcesOfType:#"png" inDirectory:#"Module_Tests"];
NSMutableArray *moduleImageArray = [[NSMutableArray alloc] initWithCapacity:[moduleArray count]];
for (NSString *path in moduleArray) {
[moduleImageArray addObject:[UIImage imageWithContentsOfFile:path]];
}
self.moduleArray = [NSArray arrayWithArray:moduleArray];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupCollectionView];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.moduleView setPagingEnabled:YES];
[self.moduleView setCollectionViewLayout:flowLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark -
#pragma mark UICollectionView methods
- (void)setupCollectionView {
[self.moduleView registerClass:[VLModuleCollectionViewCell class] forCellWithReuseIdentifier:#"VLModuleCollectionViewCell"];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.moduleView setCollectionViewLayout:flowLayout];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.moduleArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
VLModuleCollectionViewCell *cell = (VLModuleCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"VLModuleCollectionViewCell" forIndexPath:indexPath];
cell.titleLabel.text = #"Module Title Goes Here";
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(235, 147);
}
#end
I had a similar issue with labels overwriting themselves in collectionView, try calling your updateCell method in awakeFromNib, this did the trick for me.
Hi in my app i have to load images to UITableViewCell .which are coming from the server.so the problem is when ever i scroll the tableview images are loading every time and its loading lazy so i tried to stop reusing cells but its not working ,How to stop reusing the cells in UITableView.
my code is
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"Cell";
RestaurantCustomCell *cell =(RestaurantCustomCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *topLevelObjects ;
topLevelObjects= [[NSArray alloc]init];
if(cell==nil)
{
topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RestaurantCustomCell" owner:self options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (RestaurantCustomCell *) currentObject;
break;
}
}
}
NSDictionary *dict=[restauarantsArr objectAtIndex:indexPath.row];
NSString *imgStr=[dict valueForKey:#"Img"];
[self processImageDataWithURLString:imgStr andBlock:^(NSData *imageData) {
if (self.view.window)
{
UIImage *img = [UIImage imageWithData:imageData];
if(img!=nil)
{
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
[img drawInRect:CGRectMake(0,0,100,100)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
cell.restaurantImg.image=newImage;
UIGraphicsEndImageContext();
}
}
}];
cell.nameLbl.text=[dict valueForKey:#"Restaurants"];
cell.typeLbl.text=[dict valueForKey:#"Rest_Cuisine"];
cell.timingsLbl.text=[dict valueForKey:#"Rest_Timings"];
cell.categoryLbl.text=[dict valueForKey:#"Rest_Category"];
cell.addressLbl.text=[dict valueForKey:#"Address"];
return cell;
}
You can not doing this in default table view cell. If you want to create this kind of things then you need to create custom tableview cell anbd do it what you want.
You have to make a custom cell like that:
RestaurantCustomCell.h
#import <UIKit/UIKit.h>
#interface RestaurantCustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *nameLbl;
#property (weak, nonatomic) IBOutlet UILabel *typeLbl;
#property (weak, nonatomic) IBOutlet UILabel *timingsLbl;
#property (weak, nonatomic) IBOutlet UILabel *categoryLbl;
#property (weak, nonatomic) IBOutlet UILabel *addressLbl;
#property (weak, nonatomic) IBOutlet UIImageView *restauranImg;
#end
RestaurantCustomCell.m
#import "RestaurantCustomCell.h"
#implementation RestaurantCustomCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)prepareForReuse{
self.nameLbl.text = #"";
self.typeLbl.text = #"";
self.timingsLbl.text = #"";
self.categoryLbl.text = #"";
self.addressLbl.text = #"";
}
#end
after in IB you add a new UITableViewCell at your UITableView and the class of it with you new custom cell set the Identify ID like "RestaurantCustomCell" add your labels and imageView to your custom cell and connect the Outlet, then you modify you tableView:cellForRowAtIndexPath: like that:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"RestaurantCustomCell";
RestaurantCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *dict=[restauarantsArr objectAtIndex:indexPath.row];
NSString *imgStr=[dict valueForKey:#"Img"];
[self processImageDataWithURLString:imgStr andBlock:^(NSData *imageData) {
if (self.view.window)
{
UIImage *img = [UIImage imageWithData:imageData];
if(img!=nil)
{
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
[img drawInRect:CGRectMake(0,0,100,100)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
cell.restaurantImg.image=newImage;
UIGraphicsEndImageContext();
}
}
}];
cell.nameLbl.text=[dict valueForKey:#"Restaurants"];
cell.typeLbl.text=[dict valueForKey:#"Rest_Cuisine"];
cell.timingsLbl.text=[dict valueForKey:#"Rest_Timings"];
cell.categoryLbl.text=[dict valueForKey:#"Rest_Category"];
cell.addressLbl.text=[dict valueForKey:#"Address"];
return cell;
I have a collectionview controller and a collectionviewcell. FOr the collectionviewcell I have a custom class. I am trying to set the uiimage and it isn't working.
Thank you in advance!.
Method in collectionview controller where I am trying to set the image.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier=#"Cell";
CollectionVIewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
;
CollectionVIewCell *feederCell = (CollectionVIewCell*)[_availableFilters objectAtIndex:indexPath.row];
cell.labelDisplay.text=feederCell.filterName;
NSLog(#"selected =%#",cell.labelDisplay.text);
if (feederCell.isSelected) {
UIImageView *imageView=[[UIImageView alloc]init];
//process string name
NSString*filePath =[NSString stringWithFormat:#"%#.png",feederCell.filterName];
NSArray* words = [filePath componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
filePath=[words componentsJoinedByString:#""];
cell.FilePath=filePath;
//image
UIImage *image = [UIImage imageNamed:filePath];
[imageView setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[imageView setImage:image];
[cell setIconDisplay:imageView];//setting the image that won't set
}else if(!feederCell.isSelected){
UIImageView *imageView=[[UIImageView alloc]init];
NSString*filePath =[NSString stringWithFormat:#"%#.png",feederCell.filterName];
NSArray* words = [filePath componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
filePath=[words componentsJoinedByString:#""];
UIImage *image = [UIImage imageNamed:filePath];
[imageView setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[imageView setImage:image];
[cell setIconDisplay:imageView];
}
return cell;
.h file
//
// CollectionVIewCell.h
#import <UIKit/UIKit.h>
#interface CollectionVIewCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet UIImageView *IconDisplay;
#property (strong, nonatomic) IBOutlet UILabel *labelDisplay;
#property (assign,nonatomic) BOOL isSelected;
#property (strong,nonatomic)NSString*textName;
#property(strong,nonatomic)NSString*FilePath;
#end
.m file
//
// CollectionVIewCell.m
#import "CollectionVIewCell.h"
#implementation CollectionVIewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_labelDisplay.text=_textName;
_IconDisplay=[[UIImageView alloc]init];
}
return self;
}
#end
You need to add the UIImageView as a subview. Otherwise it exists but isn't displayed.