IOS:app crash due to memory warning - objective-c

My app gets crashed, when I am loading profile with thumbnail picture in UITableView.
It loads up to 5 profiles with picture properly. But, when I am creating sixth one, then loading profile in table view with picture it gets crashed, showing me the memory warning message.
Actually I have used ARC. So, I am not able to release the memory. I am only able to use the autoreleasepool to realease the memory.
Below is code I am using to load the profile in UITableView with profile picture.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
#autoreleasepool
{
static NSString *CellIdentifier=#"Cell";
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
MyProfile * objMP1 = [GlobalgroupedProfileArray objectAtIndex:[indexPath row]];
NSString *titleText =[#"Name: " stringByAppendingString:objMP1.Name];
cell.textLabel.text=titleText;
NSString *strTitle1=[#"Owner: "stringByAppendingString:[objMP1.Owner stringByAppendingString:#"\n"]];
NSString *strTitle2=[#"Breed: "stringByAppendingString:[objMP1.Breed stringByAppendingString:#"\n"]];
NSString *strTitle=[[strTitle1 stringByAppendingString:strTitle2] stringByAppendingString:[#"ID Number: "stringByAppendingString:[NSString stringWithFormat:#"%#",objMP1.IDNumber]]];
cell.detailTextLabel.text=strTitle;
cell.detailTextLabel.numberOfLines =3;
#autoreleasepool
{
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.frame.size.width-70-25, 15, 50, 50)];
imageView.image = objMP1.img;
[cell addSubview:imageView];
imageView=nil;
}
#autoreleasepool
{
// Load the image with an GCD block executed in another thread
dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);
dispatch_async(downloadQueue, ^{
CGSize newSize = CGSizeMake(50, 50); //whaterver size
UIGraphicsBeginImageContext(newSize);
[objMP1.img drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
#autoreleasepool
{
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.frame.size.width-70-25, 15, 50, 50)];
imageView.image = newImage;
[cell addSubview:imageView];
imageView=nil;
}
});
});
dispatch_release(downloadQueue);
}
[cell.imageView setImage:newImage];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
}
Any Hints?

Related

UICollectionViewCell memory leak when user click image loading all images(150) in slide objective c

Basically I want to display images in slide which are coming from server. it works for maximum 10 images. And I am displaying them in UICollectionView with Cell but when I click folder that has 100 +more images it gives me error that memory leak because it loads all images (3Gigabytes+) in one time when clicked. I tried to call by index it loads clicked image but when i swipe other images are not loading.
I resized all images with Bitmap all works but Image has too many details when zooming it's impossple to read. Is there any other way to load images one by one when Cell calls image?
Here is my LocalFileDeailViewController.m
(void) initPaging {
CGFloat width = self.scrollView.frame.size.width;
CGFloat height = self.scrollView.frame.size.height;
CGRect innerFrame = CGRectMake(0, 0, width, height);
for (int i = 0; i < self.fileList.count; i++) {
__block UIImage* Image = nil;
if ([self.ListType isEqual: #"url"]) {
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: self.fileList[i]]];
Image = [UIImage imageWithData: imageData];
} else {
NSString * filePath = (NSString *) self.fileList[i];
NSString *imageFullPath = [self.filePath stringByAppendingPathComponent:filePath];
BOOL isLoadAble = [[NSFileManager defaultManager] fileExistsAtPath:imageFullPath];
if ( isLoadAble ) {
Image = [UIImage imageWithContentsOfFile:imageFullPath];
} else {
//TODO 이미지가 없는경우 뭘 표시하나?
continue;
}
}
CGRect frame = CGRectMake(i * width, 0, width, height);
UIImageView *imgV = [[UIImageView alloc] initWithFrame:innerFrame] ;
[imgV setImage:Image];
[imgV setContentMode:UIViewContentModeScaleAspectFit];
[imgV setBackgroundColor:[UIColor blackColor]];
imgV.tag = VIEW_FOR_ZOOM_TAG;
UIScrollView *psv = [[UIScrollView alloc] initWithFrame:frame];
[psv setBackgroundColor:[UIColor blackColor]];
psv.minimumZoomScale = ZOOM_MIN;
psv.maximumZoomScale = ZOOM_MAX;
psv.zoomScale = ZOOM_SCALE;
psv.contentSize = imgV.bounds.size;
psv.delegate = self.scrollDelegate;
psv.showsHorizontalScrollIndicator = NO;
psv.showsVerticalScrollIndicator = NO;
[psv addSubview:imgV];
[self.contentView addSubview:psv];
[self.pages addObject:psv];
}
self.contentViewWidth.constant = self.fileList.count * width;
[self.scrollView setContentOffset:CGPointMake(width * self.index, 0) animated:NO];
And LocalImageGridViewController.m
#define CELL_ID #"LocalFileImageCollectionViewCell"
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LocalFileImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CELL_ID forIndexPath:indexPath];
NSString * fileName = (NSString *) self.fileList[indexPath.row];
[ cell prepareForReuse];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
[cell setImagePath:self.filePath imageName:fileName index: indexPath.row];
if (![cell superview]){
[_collectionView addSubview:cell];
}
return cell;
#pragma mark <UICollectionViewDelegate>
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
[collectionView deselectItemAtIndexPath:indexPath animated:NO]; NSLog(#"indexpath >>>> %#", indexPath);
// NSString * fileName = (NSString *) self.fileList[indexPath.row];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
LocalFileImageDetailViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"LocalFileImageDetailViewController"];
// [vc setFileName:fileName];
[vc setFileName:self.fileName];
[vc setFilePath:self.filePath];
[vc setFileList:self.fileList];
[vc setIndex:indexPath.item];
[self.navigationController pushViewController:vc animated:YES];
NSLog(#"vc >>>> %#", vc);
}
You should use UICollectionView in LocalFileDeailViewController instead of UIScrollView. Collection view load cells by demand, not on load view controller

xCode: TableView cant see/acces all cells

When I press a button called "AllOK" I want the object.selectedIndex to be 0. This works perfectly with the cells that is visible. But it won't acces the cells which isn't viewable on the app / screen. If you scroll down and get vision of them, it will check them, but i want it to do it, without having to scroll down.
Do anyone know how to get the tableview to know that it "also" got the cells that it cannot see?
My code for my tableview and for the button:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FancyCell"];
cell = nil;
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"FancyCell"];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
// add the segmentedControl when you create a new cell
UIImage *correctImageGreen = [[UIImage imageNamed:#"green.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *correctImageGul = [[UIImage imageNamed:#"gul.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *correctImageRed = [[UIImage imageNamed:#"red.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *correctImageGray = [[UIImage imageNamed:#"gray.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
NSArray *itemArray = [NSArray arrayWithObjects: correctImageGreen, correctImageGul, correctImageRed, correctImageGray, nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:itemArray];
segmentedControl.frame = CGRectMake(310, 7, 150, 30);
[cell.contentView addSubview:segmentedControl];
// add an action so we can change our model if the view changes
[segmentedControl addTarget:self action:#selector(didChangeSegmentedControl:) forControlEvents:UIControlEventValueChanged];
// use a tag so we can retrieve the segmentedControl later
segmentedControl.tag = 42;
}
// either if the cell could be dequeued or you created a new cell,
// segmentedControl will contain a valid instance
UISegmentedControl *segmentedControl = (UISegmentedControl *)[cell.contentView viewWithTag:42];
UIImage *comment = [UIImage imageNamed:#"Checkmark-hvid"];
UIImage *imageRef = [UIImage imageNamed:#"Checkmark-hvid"];
UIImageView *commentView = [[UIImageView alloc] initWithImage: comment];
UIImageView *imageRefView = [[UIImageView alloc] initWithImage: imageRef];
commentView.frame = CGRectMake(625, 5, 30, 30);
imageRefView.frame = CGRectMake(515, 5, 30, 30);
commentView.tag = 98;
imageRefView.tag = 99;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
boolean_t didGetStates = [defaults boolForKey:#"didGetStates"];
MBFancyObject *object = _objects[indexPath.row];
if (didGetStates) {
// State
NSDictionary *dic = [tableData objectAtIndex:indexPath.row];
if (object.beingEdited == -1) {
int selectedState = [[dic valueForKey:#"State"] intValue];
object.selectedIndex = selectedState;
}
// Comment & ImageRef
int comment = [[dic valueForKey:#"Comment"] intValue];
int imageRef = [[dic valueForKey:#"Foto"] intValue];
if (comment == 0) {
[cell.contentView addSubview:commentView];
}
else {
[[cell.contentView viewWithTag:98]removeFromSuperview];
}
if (imageRef == 0) {
[cell.contentView addSubview:imageRefView];
}
else {
[[cell.contentView viewWithTag:99]removeFromSuperview];
}
}
cell.textLabel.text = object.title;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
segmentedControl.selectedSegmentIndex = object.selectedIndex;
object.currentIndexRow = indexPath.row;
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
return cell;
}
- (IBAction)allOK:(id)sender {
for (MBFancyObject *object in _objects) {
object.selectedIndex = 0;
object.beingEdited = 0;
}
[[self tableView] reloadData];
}
So I hadn't noticed this at my first comment, but your problem here is obvious. You are not properly dequeueing cells from the cell pool, and therefore when you scroll, you are creating a brand new cell EVERY time, which causes them not to have your selected index the way you want. I am pretty sure that your solution lies right here:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FancyCell"];
cell = nil;
if (!cell) {
You are dequeuing a cell properly, but then immediately setting it to nil, meaning it will ALWAYS go through the !cell check and will ALWAYS create a new cell. Try removing this line and working with the dequeued cell.
Edit:
Since that didn't do it, this is what else I would try:
Create a call to the method willDisplayCell:forRowAtIndexPath:, and in this call check a boolean flag that you set to see if the segmented control at that index should be at index 0 or not. So basically whenever a cell is about to be shown, you check if it's segmented control should be set to index 0, and if it should, set it's index to 0.

sticky uitableview

i'm having a problem with uitableview when i scroll it up and down many times it becomes sticky and all the containing view becomes sticky too.
here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text=[NSString stringWithFormat:#" %#",
[SongsNames objectAtIndex:indexPath.row]];
UIImageView *b=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 35, 34)];
b.image=[UIImage imageNamed:#"playbuttone.png"];
[cell.contentView addSubview:b];
[b release];
UIButton *b2=[[UIButton alloc] initWithFrame:CGRectMake(260, 0, 50, 35)];
[b2 setImage:[UIImage imageNamed:#"buye.png"] forState:UIControlStateNormal];
[cell.contentView addSubview:b2];
[b2 release];
cell.textLabel.textColor=[UIColor colorWithWhite:1 alpha:1];
}
after update:
cell.textLabel.text=[NSString stringWithFormat:#" %#",[SongsNames objectAtIndex:indexPath.row]];
[cell.contentView addSubview:b];
// [b release];
[cell.contentView addSubview:b2];
//[b2 release];
cell.textLabel.textColor=[UIColor colorWithWhite:1 alpha:1];
and in the viewdidload:
- (void)viewDidLoad{
b=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 35, 34)];
b.image=[UIImage imageNamed:#"playbuttone.png"];
b2=[[UIButton alloc] initWithFrame:CGRectMake(260, 0, 50, 35)];
[b2 setImage:[UIImage imageNamed:#"buye.png"] forState:UIControlStateNormal];
}
You are reloading your images for each call of that function. When scrolling this function gets called really a lot of times which is not neccessary, in particular because your images are static and identical for each cell.
Load the two images once when the view did load, save a reference in the view controller and reuse them. When the table view requests the cell. This very likely will solve your problem.
ok for anyone who will get that confusing problem stop adding uicontrols to ur uitableviewcell and use custom cell like in this tutorial
http://www.youtube.com/watch?v=PwcBdCUZNWs

Uislider in uitableviewcell is no more auto-updated when I scroll

I'm having a little trouble with my code, and I was hoping to get some help here
I have a uitableview, in each uitableviewcell I put an individual uislider.
Each uislider, is used as a progress bar for music playing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *button = nil;
UISlider *customSlider = nil;
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIImage *image = [UIImage imageNamed:#"button_play.png"];
button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(340.0, 10.0, image.size.width, image.size.height);
button.frame = frame;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:#selector(playAudio:) forControlEvents:UIControlEventTouchUpInside];
button.tag = 4;
[cell.contentView addSubview:button];
customSlider = [[UISlider alloc] initWithFrame:CGRectMake(10, 45, 456, 20)];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 100.0;
customSlider.continuous = YES;
customSlider.tag = 3;
customSlider.value = 0.0;
[cell.contentView addSubview:customSlider];
}
else {
customSlider = (UISlider *)[cell.contentView viewWithTag:3];
button = (UIButton *)[cell.contentView viewWithTag:4];
}
return cell;
}
- (void) playAudio:(UIButton *)sender {
UIButton *button = (UIButton *)[sender superview];
UITableViewCell *currentCellTouched = (UITableViewCell *)[button superview];
UITableView *currentTable = (UITableView *)[currentCellTouched superview];
NSIndexPath *indexPath = [currentTable indexPathForCell:currentCellTouched];
//currentCellPlaying type of UITableViewCell and accessible from the rest classe
currentCellPlaying = currentCellTouched;
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:NSLocalizedString([listFilesAudio objectAtIndex:indexPath.row], #"") ofType:#"mp3"]];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
player.delegate = self;
[player prepareToPlay];
[(UISlider *)[currentCellTouched.contentView viewWithTag:3] setMaximumValue:[player duration]];
[(UISlider *)[currentCellTouched.contentView viewWithTag:3] setValue:0.0];
NSTimer *sliderTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
[player play];
}
- (void)updateTime:(NSTimer *)timer {
[(UISlider *)[currentCellPlaying.contentView viewWithTag:3] setValue:player.currentTime];
}
When I launch a single play, everything is okay and the progress bar is updated.
My problem is that when I scroll down/up the tableview, and the cell where the music is playing disappears, once we come back over the cell playing the music, the uislider is back to 0, and is not updated anymore... (a NSLOG confirms that we still go inside "updateTime" method)
If you have the solution for my problem, I would be very glad to read it.
Thank you in advance.
Otium's answer is not completely right, but it goes in the right direction. The celle are not all the same object, but (actually you implemented it that way) cells that leave visible area by scrolling are reused for display of others, scrolling into visible area. So when the cell playing the music becomes visible again, another slider object then the original one is displayed inside it. Moreover the currentCellPlaying object (maybe) isn't shown anymore or is shown as another cell. So when you update it's viewWithTag:3 you (sometimes) won't see that.
What you should do, is storing a "indexCurrentPlaying" instead of cell or slider references. With that index you can decorate the cell at the end of cellForRowAt.... And you can update the slider of exactly the cell at that Index inside updateTime.
Hope that helps.
EDIT:
Some not-tested code that should work (maybe with some fixes, but it explains the idea, I think):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIButton *button = nil;
UISlider *customSlider = nil;
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIImage *image = [UIImage imageNamed:#"button_play.png"];
button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(340.0, 10.0, image.size.width, image.size.height);
button.frame = frame;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:#selector(playAudio:) forControlEvents:UIControlEventTouchUpInside];
button.tag = 4;
[cell.contentView addSubview:button];
customSlider = [[UISlider alloc] initWithFrame:CGRectMake(10, 45, 456, 20)];
customSlider.minimumValue = 0.0;
customSlider.maximumValue = 100.0;
customSlider.continuous = YES;
customSlider.tag = 3;
customSlider.value = 0.0;
[cell.contentView addSubview:customSlider];
}
else
{
customSlider = [cell viewWithTag:3];
}
if([indexPath isEqual:currentPlayingIndexPath])
{
currentPlayingSlider = customSlider;
[self updateTime];
}
else if(customSlider == currentPlayingSlider)
{
currentPlayingSlider = nil;
}
return cell;
}
- (void) playAudio
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:NSLocalizedString([listFilesAudio objectAtIndex:currentPlayingIndexPath.row], #"") ofType:#"mp3"]];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
player.delegate = self;
[player prepareToPlay];
NSTimer *sliderTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
[player play];
}
- (void)updateTime:(NSTimer *)timer
{
[currentPlayingSlider setValue:player.currentTime];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
currentPlayingIndexPath = indexPath;
currentPlayingSlider = [cellForRowAtIndexPath: currentPlayingIndexPath];
[self playAudio];
}
Be careful with NSIndexPath isEqual. Seems to answer different in different versions of the SDK (look here) ... Since you only need the row it could be changed to currentPlayingIndexPath.row == indexPath.row
A UItableView uses dequeable cells, so all your cells are basically the same object. In the cellForRowAtIndexPath method you should set the progress of the slider again.

UITableViewCell with images in different dimensions

I'm trying to use my ReusableCell for cells with images in different dimensions. The images are put inside a 220x150 black box with with scaling UIViewContentModeScaleAspectFit.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NewsTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NewsItem *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.imageUrl]];
[cell.imageView setImage:[[UIImage alloc] initWithData:data]];
[cell.imageView setBackgroundColor:[UIColor blackColor]];
[cell.imageView setContentMode:UIViewContentModeScaleAspectFit];
CGRect imageViewFrame = cell.imageView.frame;
imageViewFrame.size.width = 220;
imageViewFrame.size.height = 150
[cell.imageView setFrame:imageViewFrame];
[cell.textLabel setText:item.title];
return cell;
}
The above code results in a layout like below and the images are sometimes changing when scrolling in the table view.
Instead of this unstructured layout, I would like the images to be aligned like this:
What am I doing wrong with this ReusableCell?
EDIT1:
I'm trying to create an imageView and add this imageView as a superview to cell.contentView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NewsTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NewsItem *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
UIImage *placeholderImage = [UIImage imageNamed:#"ImagePlaceholderThumb"]; //220x150
UIImageView *imageView = [[UIImageView alloc] initWithImage:placeholderImage];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:item.imageUrl]];
[imageView setImage:[[UIImage alloc] initWithData:data]];
[imageView setBackgroundColor:[UIColor blackColor]];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
CGRect imageViewFrame = imageView.frame;
imageViewFrame.size.width = placeholderImage.size.width;
imageViewFrame.size.height = placeholderImage.size.height;
[imageView setFrame:imageViewFrame];
[cell.contentView addSubview:imageView];
[cell.textLabel setText:item.title];
return cell;
}
The above code results in the following:
It is like some of the images are visible in two cells. It seems that they are not keeping the size I've set in the imageViewFrame. Do you know why?
A quick fix would be using content mode UIViewContentModeScaleAspectFill. Images will be stretched in one or both dimensions to fill up the whole image view bounds.
You really need subclassing UITableViewCell to do this right.
Thre is a lazy solution adding a new UIImageView and using a spacer, as Keller told you in his answer (feel free to accept his answer, this is just the missing code).
Extract of tableView:cellForRowAtIndexPath::
...
cell.textLabel.text = [NSString stringWithFormat:#"Cell #%i", indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"spacer.png"]; /* spacer is 64 x 44 */
/* image view width should be ~ 64 px, otherwise it will overlap the text */
UIImageView *iv = [[UIImageView alloc] initWithFrame:(CGRect){.size={64, tableView.rowHeight}}];
switch (indexPath.row) {
case 0:
iv.image = [UIImage imageNamed:#"waterfall.png"];
break;
/* etc... */
}
if (indexPath.row < 3) {
/* add black bg to cell w/ images */
iv.backgroundColor = [UIColor blackColor];
}
iv.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:iv];
...
The table will look like this:
You need to set the placeholder (spacer.png above) in the existing cell image view. It will push the text label to the right.
You can use aspect fill and remove the background color bit:
iv.contentMode = UIViewContentModeScaleAspectFill;
The table will look wrong because the image is drawn outsite the bounds:
Just clip to bounds to get a better result:
iv.clipsToBounds = YES;
Create a UIImageView subview for each cell and it to the contentView. Each UIImageView contains an image with a consistent frame but with option UIViewContentModeScaleAspectFit. Then just Set the background color of the UIImageView to black.
I just confirmed this works, but you need to also create a placeholder spacer image to make sure the textLabel moves out of the way. Just make it the same dimensions of your image (with the letter boxing).
- (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];
//spacer
cell.imageView.image = [UIImage imageNamed:#"placeholder"];
//imageview
UIImageView *thumbnail = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 44)];
thumbnail.tag = kThumbTag;
thumbnail.backgroundColor = [UIColor blackColor];
thumbnail.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:thumbnail];
}
// Configure the cell...
cell.textLabel.text = [NSString stringWithFormat:#"Cell %d", indexPath.row];
cell.imageView.frame = CGRectMake(0, 0, 80, 44);
UIImageView *thumb = (UIImageView*)[cell.contentView viewWithTag:kThumbTag];
if (indexPath.row == 0) {
[thumb setImage:[UIImage imageNamed:#"image1.png"]];
} else {
[thumb setImage:[UIImage imageNamed:#"image2.png"]];
}
return cell;
}
Obviously, this example isn't lazy loading the images (I didn't realize you were loading them from a URL). For that, I would use a subclass with EGOImageView or something of the like.