Image in reused cell in a TableView not being cleared from ImageVIew - iphone

I have a Tableview containing cells with images, however the cells that are reused still contain the image from the previous cell that is being reused until the new image is downloaded and set.
I have tried setting the image to nil. (imageV is a subclass of HJManagedImageV, source can be found here: HJManagedImageV
[cell.imageV setImage:nil];
the setter
-(void)setImage:(UIImage *)theImage{
if (theImage==image) {
//when the same image is on the screen multiple times, an image that is alredy set might be set again with the same image.
return;
}
[theImage retain];
[image release];
image = theImage;
[imageView removeFromSuperview];
self.imageView = [[[UIImageView alloc] initWithImage:theImage] autorelease];
[self addSubview:imageView];
[imageView setNeedsLayout];
[self setNeedsLayout];
[loadingWheel stopAnimating];
[loadingWheel removeFromSuperview];
self.loadingWheel = nil;
self.hidden=NO;
if (image!=nil) {
[callbackOnSetImage managedImageSet:self];
}
}
I have a workaround for by setting imageV to hidden but then I lose the loading spinner and I'd really like to know why setting it to nil isn't working.
Anyone have any ideas, cause I'm all out of them. Or am I missing a step somewhere.

Are the cells a subclass of UITableViewCell? If yes, I would try to implement the method prepareForReuse and see if can solve the problem there.
Hope this helps =)

Don't set it to nil, nor hide it.
We use a similar class and what we do for such cases is to set a start image to be displayed until the new image loads.
So in your case you could simply set the image as a blank jpg/png inside your bundle instead of nil

Related

How to assign separate memory spaces of same type of class

Hi my program adds small Images to main view. I have this undo button to remove recently added Image(subView). It works ok when it has all different Images, But when there are two same images it occurs error.
I think this is because it both points the same original png file. But I have no idea how to fix it. Please give me some hint.
add{
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"pah%d",tagNum]];
TouchImageView *touchImageView = [[TouchImageView alloc] initWithFrame:imageRect];
imageCounter++;
touchImageView.tag = imageCounter;
touchImageView.image = image;
touchImageView.center = CGPointMake(160.0, 230.0);
[view addSubview:touchImageView];
}
undo{
[[self.view viewWithTag:imageCounter] removeFromSuperview];
imageCounter--;
}
I doubt that its your problem here but imageNamed: caches the image in memory with an internal caching system. Every time you ask for [UIImage imageNamed:#"foo"] you get the same UIImage instance.
You probably want to be using imageWithContentsOfFile: instead which returns a unique instance of a UIImage.
Try that and see if it makes a difference.
if you just have to remove recently added image...
then each time where you are adding the image store its reference like this - it will work well with ARC...
UIImageView *imageView = touchImageView;
then in your remove Recently added image button click's
for(UIImageView *iV in view.subviews)
{
if(iV == imageView)
{
[iV removeFromSuperView];
}
}
i think it will work ...

how to add subviews from array to a uiview?

i have my subviews stored in an array...what i want is to place these subviews to my main view from array....
for(int i=0;i<[imageViewArray count];i++)
{
NSLog(#" image array count is %d",[imageViewArray count]);
// countlayers= countlayers+1;
// [canvasView insertSubview:[imageViewArray objectAtIndex:i] atIndex:countlayers];
[canvasView addSubview:[imageViewArray objectAtIndex:i]];
}
can you tell me what i am doing wrong
If imageViewArray really contains initialized views, and if those views already have correct frame attributes, you're doing nothing wrong (even though your code could be more elegant).
Also, of course, we have to make sure that canvasView is indeed initialized and visible on the screen. Try setting its backgroundColor to something noticeable:
canvasView.backgroundColor = [UIColor greenColor];
Once you are sure the canvasView is actually being displayed, I would suggest using fast enumeration, which makes going through the array nicer, and logging your new subviews to make sure their frames are like you want them.
for (UIView *imageView in imageViewArray) //this is fast enumeration. You can get it through code completion by typing forin
{
NSLog(#"%#", imageView); //let's take a look at the imageView. What is its frame?
[canvasView addSubview:imageView];
}
Used enumeration to add images on your canvas View using imageViewArray and probably you are also missing with the setting frame of the images.
for (UIImageView *imageView in imageViewArray) //enumeration.
{
//let's set frame for image view before adding to canvasView
[imageView setFrame:CGRectMake(x,y,w,h)];
//Also make sure imageView has image or not
if(imageView.image)
[canvasView addSubview:imageView];
}

Add a UIImageView to a Tableview

I have an asychronous image loader which loads images (JImage) in a UIImageview. I want to display these in a tablecell. Obviously i cant set cell.imageView.image because i dont have an image, i just have a view.
How do i set the UIImageview to the tablecell? cell.backgroundView works though, but that paints over the whole cell.
The JImage code is:
NSURL *theUrl=[NSURL URLWithString:imageURL];
JImage *photoImage=[[JImage alloc] init];
[photoImage initWithImageAtURL:theUrl];
[photoImage setContentMode:UIViewContentModeRedraw];
[photoImage setFrame:CGRectMake(0.0f, 0.0f, 40.0f, 65.0f)];
cell.backgroundView = photoImage;
[photoImage release];
which in the JImage.m:
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[self setImage:[UIImage imageWithData: data]];
}
use this code and set frame according to your need.
UIImage *imagearrow = [UIImage imageNamed:#"arrow.png"];
UIImageView *imgarrow=[[UIImageView alloc] initWithFrame:CGRectMake(290, 25, 7, 15)];
imgarrow.image =imagearrow;
[cell addSubview:imgarrow];
[imagearrow release];
You don't need to use JImage if all you want to do is load the image asynchronously. One easy way to do this is with GCD and blocks, like so: https://github.com/ChrisTec/iPhone-Book-CodeSamples/blob/master/Chapter%2013/RealEstateViewer%2013.2.5/RealEstateViewer/ImageTableViewController.m
Here's a sample chapter of the book Objective-C Fundamentals which I've co-authored that explains this code in depth: http://www.manning.com/fairbairn/OCF_sample_ch13.pdf
To sum it up: When the cell is requested, you look if you already have downloaded the image. If you have, you display it. If not, you display a spinner and start an async GCD block that will fetch the image. One that block is done, it will run another block on the main thread that switches the spinner out for the image. That's all.
I think you should take a different approach to this. Instead of putting your JImage in the cell, hold it somewhere else in the view controller, an NSArray is usually convenient. Then populate the cells with either placeholder images or just leave them empty.
So let's say you have an array with all the JImages that are loading, when the JImage in the position x of the array finishes loading, you reload that specific cell as it follows:
NSIndexPath indexPath = [NSIndexPath indexPathForRow:x inSection:0];
[self.tableView reloadRowsAtIndexPaths:x withRowAnimation:NO];
And in your cellForRow:AtIndexPath you just have to take the image from the JImage object held in the array.
I hope this helps you

UIImageView showing the image only after changing tabs in the UITabBarViewController

I have a UIScrollViewController that has a UIScrollView which holds an UIImageView inside.
In loadView of the the scroll view controller I download the image by calling a function, that's supposed to do the downloading on a different thread. I call this function from my loadView and then put the imageview inside the scrollview, and set the scrollview as the view of the controller.
The problem is I can't see the image when I run the program, after clicking a row in the tableView (which is supposed to push the scrollview with the image in it). However, if I change tabss (in the tabbarviewcontroller) and come back to this tab. The image will show.
So I think the image download happens, but I somehow have a problem showing it instantly on the screen. It only appears after I come back to it. What do I seem to be doing wrong? I'm new to threads so I suspect it's a problem with that. Also my code was working before I made it so that it would do the download in another thread, so I'm pretty sure it is related to that.
This is the function in the Photo.m which is an Entity in Core Data. This is supposed to do the download
- (void)processImageDataWithBlock:(void (^)(NSData *imageData))processImage {
NSString *url = self.imageURL;
dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("Flickr download", NULL);
dispatch_async(downloadQueue, ^{
NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:url];
dispatch_async(callerQueue, ^{
processImage(imageData);
});
});
}
This is my loadView method in the PhotoScrollViewController.m
- (void)loadView {
[image processImageDataWithBlock:^(NSData *imageData) {
UIImage *imageToBeShown = [UIImage imageWithData:imageData];
imageView = [[UIImageView alloc] initWithImage:imageToBeShown];
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
scrollView = [[UIScrollView alloc] initWithFrame:applicationFrame];
scrollView.delegate = self;
scrollView.contentSize = imageToBeShown.size;
[scrollView addSubview:imageView];
self.title = image.title;
self.view = scrollView;
}];
}
Edited to add extra information that was added as an answer
Adding [super loadView] to my loadView method solved the issue. However, the documentation says that I shouldn't be calling super loadView from my loadView.
I tried moving the code to viewDidLoad and that works as well. But really this is the code that's setting the view so I feel like I should be putting it in loadView. But then it doesn't work when I use this multi threading mechanism for download.
Is this because the download is somehow interfering with me setting the view in loadView?
It seems loadView completes before the image download is done. You need some way of calling [imageView setNeedsDisplay] when image download is complete. You need some method that gets called when image download is done that accesses the imageView (perhaps using viewWithTag) from the scrollView and calls [imageView setNeedsDisplay];

Asynchronous image load into TableView cell

Im trying to load a single image into the grouped table cell. I found a piece of code on the internet and modified it. Original code is using UIViews to display image, which is not what I need, however original code works of course. PLease help me to make this code work to display an image in a sigle cell for grouped tableview. My TableView has only one row and it has UITableViewCellStyleDefault style.
Original Code
Here is my modified method, this is the core method.
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[connection release];
connection=nil;
UIImage *img = [UIImage imageWithData:data];
self.image = img;
self.frame = self.bounds;
[self setNeedsLayout];
[data release];
data=nil;
}
This is how I use it to display image in my TableView Cell cellForRowAtIndexPath method.
CGRect frame;
frame.size.width=75; frame.size.height=75;
frame.origin.x=0; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
[asyncImage loadImageFromURL:imageURL];
cell.imageView.image = asyncImage.image;
In that code you posted, the image of the AsyncImageView doesn't get set until after the connection finishes loading and it actually creates the image. Problem is, you're setting it's image into the cell immediately. That's not going to work!
You're going to want to make a custom cell class (subclass UITableViewCell) and use that cell in your table. There's lots of sample code showing how to use custom cells and lay them out with views. Instead of using UITableViewCell's standard imageView, create your own layout and use an AsyncImageView to show your image. Then it should work.