Slow speed while converting NSDATA to UIImage - iphone

I have some images in the array in the form of NSDATA.and i am showing them on page in page controller example 6 at a time.
But they are taking time to get convert in to UIImage that's why scrolling get slow dowwn is we have any other option?
i am using following code to convert them into NSDATA.
[UImage imageWithData:data];

From http://www.switchonthecode.com/tutorials/loading-images-asynchronously-on-iphone-using-nsinvocationoperation :
In your main thread:
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
[operation release];
Other methods required:
- (void)loadImage {
NSData* imageData = //however you're getting your NSData
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image {
[imageView setImage:image]; //UIImageView
}

Related

Can't seem to call NSInvocationOperation with an NSArray

I am trying to load an image in the background from a url. The code works great if all I pass is the NSUrl. If I try to pass an NSArray with additional variables, it never gets called:
This code works great, LoadImage2 is called which in turn nicely calls ImageLoaded2.
- (void)LoadBackgroundImage2: (char*)pImageURL
{
NSString* pImageURLString = [NSString stringWithFormat:#"%s", pImageURL];
NSLog( #"LoadBackgroundImage2: %#", pImageURLString );
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(LoadImage2:)
object:pImageURLString];
[queue addOperation:operation];
[operation release];
}
- (void)LoadImage2: (NSString*)pImageURL
{
NSLog( #"LoadImage2: %#", pImageURL );
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:pImageURL]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(ImageLoaded2:) withObject:image waitUntilDone:NO];
}
This code does not work. LoadImage never gets called:
- (void)LoadBackgroundImage: (char*)pImageURL :(int)textureID :(int)textureType
{
printf( "LoadBackgroundImage( %s, %d, %d)\n", pImageURL, textureID, textureType );
NSString* pImageURLString = [NSString stringWithFormat:#"%s", pImageURL];
NSArray* pUrlAndReferences = [[[NSArray alloc] initWithObjects: pImageURLString, textureID, textureType, nil] autorelease];
NSOperationQueue *queue = [[NSOperationQueue new] autorelease];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(LoadImage:)
object:pUrlAndReferences];
[queue addOperation:operation];
[operation release];
}
- (void)LoadImage: (NSArray*)pUrlAndReferences
{
NSString* pImageUrl = [pUrlAndReferences objectAtIndex: 0];
int textureId = [ [ pUrlAndReferences objectAtIndex: 1 ] intValue ];
int textureType = [ [ pUrlAndReferences objectAtIndex: 2 ] intValue ];
NSLog( #"\n\nLoadImage: %#, %d, %d\n", pImageUrl, textureId, textureType );
NSData* pImageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:pImageUrl]];
UIImage* pImage = [[[UIImage alloc] initWithData:pImageData] autorelease];
NSArray* pImageAndReferences = [[[NSArray alloc] initWithObjects: pImage, textureId, textureType, nil] autorelease];
[pImageData release];
[self performSelectorOnMainThread:#selector(ImageLoaded:) withObject:pImageAndReferences waitUntilDone:NO];
}
Anyone have any ideas why LoadImage doesn't get called?
Thanks.
My guess is your not retaining your queue. Here's what's happening
Your array (autoreleased) goes into the NSInvocationOperation and it's being retained (no problem)
Your NSInvocationOperation goes into the queue (retained) and then it's released. No problem here since the retain count is still one: 1 (alloc) + 1 (retain) - 1 (release) = 1 = not dealloced.
Your queue is alloced (new = alloc+init) and then autoreleased, but it's not being retained elsewhere. Here comes the problem: since you have autoreleased the queue, once the method LoadBackgroundImage is finished the queue has a retain count of 0 and it's automatically released, therefore, your Invocation won't be executed.
You can try if that's the problem by just removing the autorelease call from the queue. If I'm correct your code should work. But be aware that that is not a good solution because you're loosing memory. It's just to see if it works.
You should definitely make a class, a singleton, an instance variable or whatever you like to retain that instance of the queue. Also, it's a good idea to only have one queue for all the LoadBackgroundImage calls instead of creating a new queue every time.

Parse image issue in Iphone

I have a array which have a one content image URL for key "Image". I want to show that image in my table view.
How to do it .Please give me suggestion.
You can search in google using "lazy loading image for tableview".
It is also available with apple example.
img_view = [[UIImageView alloc]init];
img_view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
img_view.frame = CGRectMake(0,0,130, 75);
activityIndicator = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
[img_view addSubview: activityIndicator];
activityIndicator.center = CGPointMake(50,30);
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:[[xmlParser data1] objectAtIndex:indexPath.row]];
[queue addOperation:operation];
[operation release];
[cell.contentView addSubview:img_view];
-(void)loadImage:(Book *)book
{
[activityIndicator startAnimating];
NSString *imgurl=[book image_url];
NSURL *url=[[NSURL alloc]initWithString:imgurl];
NSData *img=[[NSData alloc]initWithContentsOfURL:url];
UIImage *image=[UIImage imageWithData:img];
img_view.image=image;
[activityIndicator stopAnimating];
}

Error in Load image in NSThread?

I have a url which contain image address, i want to load that image via NSThread but i am facing problem. I am doing thing like this.
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 10, 55, 57)];
[NSThread detachNewThreadSelector:#selector(showImage) toTarget:self withObject:nil];
[self.view addSubview:imageView];
- (void) showImage {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:temp.strUrl];
UIImage *chart = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
[url release];
imageView.image = chart;
[pool release];
}
Please help me on that.
the problem is here.
[url release];
you are not supposed to release the url object . as you haven't alocated it, may be that is what you are facing problem with.

UIButton image asynchronously

I have a bunch of UIButton in a UIScrollView and each UIButton takes an image from a URL. What is the easiest way so that the image will be loaded asynchronously?
For example, the usual way is:
[button setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
but this blocks the UI, I don't want it to
You can try this
[self performSelectorInBackground:#selector(loadImag) withObject:nil];
In loadImage function load the image from url and then assign it to the button.
I am not sure this will work for you...As I am a beginner in objective C development
Try with an NSInvocationOperation, make an synchronous request for each image button... Pass the button as parameter, something like this i mean...
Init the operation queue (maybe on init):
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
start the operation invocation for each button...
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(getImageFromURL:)
object:[NSDictionary dictionaryWithObjectsAndKeys:#"http://getMyImage.com/resource.jpg", #"url", button, #"button", nil]];
[queue addOperation:operation];
[operation release];
this can be your getImageFromURL: selector
- (void) getImageFromURL:(NSDictionary*)dict
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLFromString:[dict objectForKey:#"url"]];
UIButton *button = [dict objectForKey:#"button"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
UIImage *image = [[UIImage alloc] initWithData:data];
// Finally set the button image and release image ...
[pool drain];
}
Don't forget release queue on dealloc...
Hope this helps! :)
I guess it is alright, if you block while loading one single image? The problem is that you have many of them? If so, then I would do like this (no threads needed):
#define DELAY 0.1 // you may set it to 0 as well
...
[self performSelector:#selector(setupButton:)
withObject:[NSNumber numberWithInt:0]
afterDelay:DELAY];
...
-(void)setupButton:(NSNumber*)count
{
UIButton *button = [self buttonFromMyScrollViewWithCount:count.intValue];
[button setImage:...];
if (count.intValue < self.numberOfButtonsInMyScrollView)
[self performSelector:#selector(setupButton:)
withObject:[NSNumber numberWithInt:count.intValue + 1]
afterDelay:DELAY];
}

stopping a photo from a new thread to load

I'm loading images with this class. I need help on how to stop them from loading when dealloc is called. This class is extending UIImageView. Also any other advice for designing the class is appreciated, i'll want for example to dispatch the loaded bytes.
#implementation RCPhoto
- (id)initWithFrame:(CGRect)frame delegate:(id)d {
if ((self = [super initWithFrame:frame])) {
// Initialization code
delegate = d;
self.contentMode = UIViewContentModeScaleAspectFit;
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#pragma mark Load photo
- (void)loadImage:(NSString *)path {
// Create a new thread for loading the image
[NSThread detachNewThreadSelector:#selector(load:)
toTarget:self
withObject:path];
}
- (void)load:(NSString *)path {
// You must create a autorelease pool for all secondary threads.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//NSLog(#"RCPhoto loadImage into a new thread: %#", path);
NSURL *url = [NSURL URLWithString: path];
NSData *data = [NSData dataWithContentsOfURL: url];
UIImage *image = [[UIImage alloc] initWithData: data];
[self performSelectorOnMainThread: #selector(performCompleteEvent:)
withObject: image
waitUntilDone: NO];
[pool release];
}
- (void)performCompleteEvent:(UIImage *)image {
//NSLog(#"RCPhoto finish loading");
[self setImage:image];
self.opaque = YES;
if ([delegate respondsToSelector:#selector(onPhotoComplete)]) {
[delegate performSelector:#selector(onPhotoComplete)];
}
}
#end
dataWithContentsOfURL: is designed to block until it times out or finishes receiving a complete response. You seem interested in interrupting the background thread when its associated view is deallocated. These facts are fundamentally at odds.
If you want to terminate the request as quickly as possible when your object is going away, this can be done by making an asynchronous request with NSURLConnection and canceling it in your dealloc method. If it isn't canceled before the response is received, you'll get a callback to connectionDidFinishLoading: on your delegate, at which point you can reconstitute your UIImage from the received data.
Final code:
- (void)loadImage:(NSString *)path {
imageData = [[NSMutableData data] retain];
NSURL *url = [NSURL URLWithString: path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self setImage:image];
self.opaque = YES;// explicitly opaque for performance
[image release];
}