I have the following code and it does not work. Is there something working behind it.
[operationQueue addOperationWithBlock:^{
imageData = [NSData dataWithContentsOfURL:imageURL];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImage *image = nil;
if(imageData){
UIImage *image = [UIImage imageWithData:imageData];
cell.imageView.image = image;
}
}];
}];
Even I create a subclass of NSOperation and then alloc init it, it does not work the way I think it to. I always have to invoke start to the NSOperation subclass to run but I suppose sending start message to NSOperation runs it in the main thread rather than running in the background thread.
I want to add an alternative solution using GCD :
backgroundQueue = dispatch_queue_create("com.razeware.imagegrabber.bgqueue", NULL);
dispatch_async(backgroundQueue, ^{
/* put the codes which makes UI unresponsive like reading from network*/
imageData = [NSData dataWithContentsOfURL:imageURL];
..... ;
dispatch_async(dispatch_get_main_queue(),^{
/* do the UI related work on main thread */
UIImage *image = [UIImage imageWithData:imageData];
cell.imageView.image = image;
......; });
});
dispatch_release(backgroundQueue);
Let me know whether this one helped you ;)
Reference
Related
Im trying to load the image of my uitableviewcells in lazy mode.
I'm trying to do it in the simplest possible way, I saw a lot of examples but they were going further than my purpose.
This is what Im doing currently, and its not working:
// Configure the cell...
Info *info = [self.Array objectAtIndex:indexPath.row];
cell.textLabel.text = info.name;
cell.detailTextLabel.text = info.platform;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
//The image is downloaded in asynchronous
NSBlockOperation *downloadingImgBlock = [NSBlockOperation blockOperationWithBlock:^{
NSString* imageURL = info.imgURL;
NSData* imageData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:imageURL]];
cell.imageView.image = [UIImage imageWithData:imageData];
}];
[self.queue addOperation:downloadingImgBlock];
Why it's not working? And how could it work?
Man, AsyncImageView is your friend! Just set the image url and everything is handled for you, downloading, caching. It's awesome.
Try the following codes
......
__block UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
__block UIImage *img;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString: imageURL]]];
dispatch_async(dispatch_get_main_queue(),^{
cell.imageView.image = img;
}
});
});
......
Using the 3rd party library source code would be easiest, but here's how you would do it in code. You are going to want to make a NSMutableArray either as a property in your .h or at the top of your .m like this:
#implementation viewController{
NSMutableArray *picList;
}
and in -initWithCoder: or, whatever init you are overloading:
picList = [[NSMutableArray alloc] init];
in – tableView:cellForRowAtIndexPath: (fullPicURL is the URL):
if([self imageExists:fullPicURL]){
shoePic = [picList objectForKey:fullSmallPicURL];
} else {
NSURL *picURL = [NSURL URLWithString:fullPicURL];
shoePic = [UIImage imageWithData:[NSData dataWithContentsOfURL:picURL]];
NSDictionary *thisImage = [NSDictionary dictionaryWithObject:shoePic forKey:fullSmallPicURL];
[cachedImages addEntriesFromDictionary:thisImage];
}
where -imageExists: is a function you write which checks the dictionary for the url. The object is the picture itself, the key is the url. Then you do cell.image = showPic;, or whatever you want to call it, and you're done for cacheing. In order to load them asynchronously, do this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:shoes];
[self performSelectorOnMainThread:#selector(fetchedShoeData:) withObject:data waitUntilDone:YES];
});
and at the end of fetchedData:
[self.tableView reloadData];
then just make sure you edit –numberOfSectionsInTableView: to change itself if it has to. Might be some other things you need to do to get it working 100%, let me know
try this one, I'm using always this scheme to load images asynchronously:
(I haven't found simplest way.)
- (void)inAnyMethod {
// ...
void (^blockLoadPhoto)() = ^{
UIImage *_imageTemporary = [UIImage imageNamed:#"..."];
if (_imageTemporary) {
[self performSelectorOnMainThread:#selector(setPhoto:) withObject:_imageTemporary waitUntilDone:true];
}
};
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), blockLoadPhoto);
// ...
}
- (void)setPhoto:(UIImage *)photo {
// do something with the loaded image
}
I finally managed to do it setting the image with:
– performSelectorOnMainThread:withObject:waitUntilDone:
After the image is downloaded
I have following code for loading image from url in xml parsing endElement method :
food.image=strVal;
NSData *data=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:strVal]];
UIImage *image=[[UIImage alloc]initWithData:data];
food.myImage=image;
Although I am using this loaded images at the end of application,my application has to wait till all image get loaded. I supposed to use cache here but i am confused how to use the cache in this application. Is there any other way?
Try this code this will not create load on your main thread:-
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(queue, ^{
NSData *data=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:yourURL]];
UIImage *image=[[UIImage alloc]initWithData:data];
dispatch_sync(dispatch_get_main_queue(), ^{
[yourImageView setImage:image];
});
});
I want to load images one by one not all together.In the following code imagedata is the array containing urls from which i need to load images. Here is my code but no success.
-(void)loadSingleImage:(int)buttonTag
{
UIButton *buttonImage =(UIButton *) [self.view viewWithTag:buttonTag];
NSData *imagesubCategoryData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:[imageData objectAtIndex:buttonTag-30]]];
[buttonImage setImage:[UIImage imageWithData:imagesubCategoryData] forState:UIControlStateNormal];
}
-(void)loadImageData
{
for(int i=0;i<[imageData count];i++)
{
[self loadSingleImage:i+30];
sleep(0.1);
}
}
You can use Grand Central Dispatch to load the images one by one..
Use the following code
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString: #"http://www.gev.com/wp-content/uploads/2011/05/two_flowers.preview.jpg"];
dispatch_sync(dispatch_get_main_queue(), ^ {
[cell.cellImage setImageWithURL: url placeholderImage: [UIImage imageNamed: #"twitter.jpg"]];
});
});
It may helps you
You can use a NSTimer.. Let me known if you need sample code.
Do not use sleep(), instead use a runloop if you must delay:
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
for(int i=0;i<[imageData count];i++)
{
[self loadSingleImage:i+30];
NSDate* dateLimit = [NSDate dateWithTimeIntervalSinceNow:0.1];
[currentRunLoop runUntilDate:dateLimit];
}
But a better solution is GCD.
I have array of image url. I want to show the images into UIImageView.
Now I convert the URL to NSData and then convert that into UIImage and then try to load that into UIImageView.
But it takes a lot of time to do this.
Is there a better way where in I can load the images in a faster and better manner?
Despite all of the answers on here telling you to do this in one line of code, it will sadly make no difference to the URL connection speed OR data / image decoding. If you want a faster way to TYPE the code then fine, but I would use category added to UIImageView....
#interface UIImageView (URL)
- (void)loadFromUrl:(NSString *)aUrl;
#end
#implementation UIImageView (URL)
- (void)loadFromUrl:(NSString *)aUrl {
NSURL *url = [NSURL urlWithString:aUrl];
NSData *data = [NSData dataWithContentsOfURL:url]
UIImage *image = [UIImage imageWithData:data];
if(image != nil) {
[self setImage:image];
}
}
#end
Now you can include the header and do...
[myImageView loadFromUrl:#"http://myurl.com/image.jpg"];
For more categories (I will be adding this one to my list!) check here. Those are all my useful ones, you may find them useful too! :)
Use everything in a single statement.
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:MyURL]]];
[UIImage imageWithData:[NSData dataWithContentsOfURL:]]
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
try this:-
image is UIImage and imageView is UIImageView
NSData *receivedData = [NSData dataWithContentsOfURL:#"yoururl"];
self.image=nil;
UIImage *img = [[UIImage alloc] initWithData:receivedData ];
self.image = img;
[img release];
[self.imageView setImage:self.image];
How do you download an image and turn it into a UIImage?
NSURL *url = [NSURL URLWithString:#"http://example.com/image.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
However, this isn't asynchronous.
You should keep in mind that loading the image data with the sample code you've provided in your own answer will block the main thread until the download has completed. This is a useability no-no. The users of your app will think your app is unresponsive. If you want to download an image, prefer NSURLConnection to download it asynchronously in its own thread.
Read the Apple documentation about async downloads with NSURLConnection.
When your download completes, you can then instantiate your UIImage from the data object:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (requestData)
{
self.image = [[[UIImage alloc] initWithData:requestData] autorelease];
}
}
Where requestData and image are instance variables of your containing class, and image is a retained property. Be sure to release image in the dealloc routine of the class, e.g. using self.image=nil;.
It is true that Asynchronous loading is a must, but you can also achieve that with a background call if you just need a simple solution.
[self performSelectorInBackground:#selector(loadImage) withObject:nil];
- (void)loadImage
{
NSURL * url = [NSURL URLWithString:#"http://.../....jpg"];
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
if (image)
{
// Success use the image
...
}
else
{
// Failed (load an error image?)
...
}
}
You can load an image in a UIImageView from a URL without blocking the UI thread simply using the dispatch_async:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:myURL];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage* image = [[UIImage alloc]initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
[myImageView setImage:image];
});
});
The first dispatch_async is used to load the image from the URL in background (without blocking the UI). The second dispatch_async is used to actually inject the image just loaded in the UIImageView. Please, note that the second dispatch_async is designed to work on the main thread (the UI thread) that is, indeed, the thread used to update the UI.
There is a really good example here using blocks: http://ios-blog.co.uk/iphone-development-tutorials/uiimage-from-url-%E2%80%93-simplified-using-blocks/
Based on #philfreo's answer I created a NSURL Extension in swift using BrightFutures (for the asynchronous callback:
extension NSURL{
func downloadImage() -> Future<UIImage, NSError>{
let promise = Promise<UIImage, NSError>()
Queue.global.async{
if let data = NSData(contentsOfURL: self){
if let image = UIImage(data: data){
promise.success(image)
return
}
}
promise.failure(NSError())
}
return promise.future
}
}
This then lets me do:
import BrightFutures
let someURL = ...;
someURL.downloadImage().onSuccess{ image in
// Do something with the UIImage
}
Update
A simple synchronous extension could look like this:
extension NSURL{
func downloadImage() -> UIImage?{
if let data = NSData(contentsOfURL: self){
return UIImage(data: data){
}
return nil
}
}
This is what #philfreo's answer looks like in swift:
let urlString = "http://lorempixel.com/100/100/cats/"
let url = NSURL(string: urlString)!
let data = NSData(contentsOfURL: url)
let image = UIImage(data: data!)
This works in a playground: