I'm making a request to a URL to download an image. I receive it as an NSData object, but when I try to convert it to a UIimage with imageWithData: the UIImage is not loaded. Here's my Code
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
__weak typeof(request)weakRequest = request;
__block UIImage * imager;
__block NSData * image;
[request setCompletionBlock:^{
[self parseXMLFileAtFileId:[weakRequest responseData]];
if (!files){
cell.correctImage.image = [UIImage imageNamed:#"sidebarPlaceholder"];
}
else{
NSURL *url = [NSURL URLWithString:[self downloading:[files objectAtIndex:0]]];
__block ASIHTTPRequest *requester = [ASIHTTPRequest requestWithURL:url];
__weak typeof(request)weakRequesting = requester;
[requester setCompletionBlock:^{
image = [weakRequesting responseData];
imager = [UIImage imageWithData:image];
cell.correctImage.image = imager;
[cell layoutIfNeeded];
}];
[requester startAsynchronous];
}
}];
Previously I got it working by explicitly stating the size of the UIImageView, but that should be taken care of by the UITableviewCell. How do I get the image to show up?
Try to run these block of code in main thread as it appeared you are trying to set the image and updating layout in background thread. Use following NSThread method right after
UIImage *imager = [UIImage imageWithData:image]
[self performSelectorOnMainThread:#selector(updateImage:) withObject:imager waitUntilDone:false];
// Define method to update the image
- (void)updateImage: (UIImage *)paramImage {
cell.correctImage.image = paramImage;
[cell layoutIfNeeded];
}
Related
I have got a productImageArray that contains url as elements of the array.
I'm trying to load those urls in my image view.
Following is the way as of how I'm loading it.
UIActivityIndicatorView *spinner=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.center=CGPointMake(160.0,240.0 );
spinner.hidesWhenStopped=YES;
[self.view addSubview:spinner];
[spinner startAnimating];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
NSData *storeImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:productImageArray[indexPath.row]]];
self.productImage.image = [UIImage imageWithData:storeImageData];
dispatch_sync(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
});
});
The problem is that,
Only the last cell of my tableview loads the image whereas the remaining cell does not load the image from the url
Is there any other better way of loading the image from url directly into my UIImage using native methods?
When I use the following code, each cell of my tableview loads the image data but still it freezes the User interface till the data is loaded completely
NSData *storeImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:productImageArray[indexPath.row]]];
self.productImage.image = [UIImage imageWithData:storeImageData];
#Anbu.Karthik answer is right.
But, maybe the simplest solution is to use something like SDWebImage no? This library will handle this issue and much more (cache, error management, proper tableview cells handling, ...).
I think you should, at least, take a few minutes to look at it: https://github.com/rs/SDWebImage
Edit:
If you use SDWebImage, and UIActivityIndicator-for-SDWebImage, you can replace your entire code by this:
[self.productImage setImageWithURL:[NSURL URLWithString:productImageArray[indexPath.row]]
usingActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
More informations on UIActivityIndicator-for-SDWebImage: https://github.com/JJSaccolo/UIActivityIndicator-for-SDWebImage
try this
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
NSData *storeImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:productImageArray[indexPath.row]]];
dispatch_sync(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
self.productImage.image = [UIImage imageWithData:storeImageData];
});
});
or try like
self.productImage.image = nil; //// [UIImage imageNamed:#"default.png"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:productImageArray[indexPath.row]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *currentImage = [UIImage imageWithData:data];
if (currentImage) {
dispatch_async(dispatch_get_main_queue(), ^{
UITableviewCell *getCurrentCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (getCurrentCell)
self.productImage.image = currentImage;
});
}
}
}];
[task resume];
NSString *url_Img1 = #"Your url";
Uiimageview *view_Image.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url_Img1]]];
I am trying to load images by their URL and store them in NSMutableArray in order. My current code works properly if I were not to care about storing the images in order, however it stores them not in order. It currently stores the images in the articleImage array based on the speed at which the asynchronous requests are completed. I have tried playing around with insertObject:AtIndex but could not get anything to work. To clarify, the NSMutableArray that I am trying to store the images in (in orderly fashion) is articleImage.
Here is some code from my viewDidLoad:
dispatch_async(dispatch_get_main_queue(), ^{
if(articleInfoJSONArray.count > 0)
{
for(int i=0; i<articleInfoJSONArray.count; i++)
{
[issueID addObject:[[articleInfoJSONArray objectAtIndex:i] objectForKey:#"issueID"]];
[articleID addObject:[[articleInfoJSONArray objectAtIndex:i] objectForKey:#"articleID"]];
NSString *imageLink = [[articleInfoJSONArray objectAtIndex:i] objectForKey:#"articleImage"];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageLink]];
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
[articleImage addObject:image];
if(articleImage.count == articleInfoJSONArray.count)
[self imagesLoaded];
});
});
}
}
});
Here is my imagesLoaded:
- (void)imagesLoaded
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
ViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"MainView"];
[self presentViewController:vc animated:NO completion:nil];
}
Try to use dispatch_group. A dispatch group monitors work that has been added to it, and it will know when that work is done. :) http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/
One way i did an image download is with NSOperationQueue and NSOperation. You could define a NSOperationQueue in your header file:
#property (strong, nonatomic) NSOperationQueue *sequentialOperationQueue;
in your implementation do:
self.sequentialOperationQueue = [[NSOperationQueue alloc] init];
self.sequentialOperationQueue.maxConcurrentOperationCount = 1;
then you can add:
for (NSDictionary *imageDict in imagesToFetch) {
ImageDownloadOperation *imgDownloadOperation = [[ImageDownloadOperation alloc] initWithImageLocationDict:imageDict];
[self.sequentialOperationQueue addOperation:imgDownloadOperation];
}
LogoDownloadOperation is a subclass of NSOperation. this way you always have only one active download and process them in the order you want. For details on NSOperation check the apple doc.
in extract i did in ImageDownloadOperation:
- (void)start {
NSURL *imageUrl = [NSURL URLWithString:self.imageDict[#"imageUrl"]];
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];
NSURLSessionDownloadTask *downloadPhotoTask = [session
downloadTaskWithURL:imageUrl
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
if (error) {
self.sessionTask = nil;
[self done];
return;
}
NSData *imageData = [NSData dataWithContentsOfURL:location];
NSBlockOperation *saveImageBlockOperation = [NSBlockOperation blockOperationWithBlock:^{
[SharedAppDelegate.entityManager saveImage:imageData
imageDict:self.imageDict
inManagedObjectContext:SharedAppDelegate.managedObjectContext];
}];
saveImageBlockOperation.qualityOfService = NSQualityOfServiceBackground;
[[NSOperationQueue mainQueue] addOperation:saveImageBlockOperation];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.sessionTask = nil;
[self done];
}];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
As you can see, i store the imageData via my AppDelegate in CoreData. Instead of my way, you could give the ImageDownloadOperation a pointer to your NSMutableArray, then you can store the data direct in your array.
You could make an array of [UIImage new] then once the task is complete
replace the empty image images[i] = newImage
EDIT
NSMutableArray *imageArray = [NSMutableArray new];
for (int i=0; i<articleInfoJSONArray.count; i++) {
[imageArray addObject:[UIImage new]];
}
for (int i=0; i<articleInfoJSONArray.count; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
//download image
imageArray[i] = downloadedImage;
});
}
My app displays a lot of images, so I am using page control to display the images in single controller.
User can able to see all the images by swiping.
I am using AFNetworking Library to show the good performance. I have used the property setImageWithUrl
// This is myCode
NSURL *myUrl = [NSURL URLWithString:#"http://mdb.scicloudsolutions.com:8001/sites/default/files/landscape_design_1.jpg"];
[imageView setImageWithUrl:myUrl];
it's not showing at first time only..
When I Print url and image
NSLog(#"Url is .. : %# image. is : %#",myUrl,imageView.image);
Response:
am receiving the url value but not image value.
It shows image is null at first time.
How to solve?
Here You Set [imageView setImageWithUrl:myUrl]; So it take time to load an Image in to ImageView.
Use SDWebImage Library For Better. Just Simple Download this Library From Link and Set Image like as
[imageView sd_setImageWithURL:url
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Use following solution for this:
#property (nonatomic, strong) NSMutableData *data
#property (nonatomic, strong) NSURLConnection *connection;
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
Add these delegate methods to your view controller:
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)incrementalData {
if (data==nil) {
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
connection = nil;
UIImage *image = [UIImage imageWithData:data];
// Set above image to your imageView.
data = nil;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/*============= YOU ARE ON BACK GROUND THREAD ==================*/
UIImageView *yourImageView=[[UIImageView alloc] init];
UIImage *img=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"pass your url here"]]];
dispatch_async(dispatch_get_main_queue(), ^(void) {
/*============= YOU ARE ON MAIN THREAD ==================*/
yourImageView.image=img;
});
});
I have some code that gets an image from a web page and displays it in an ImageView. But the image loads very slowly for some reason I don't really understand! Through my logging I can see that all the data for the image (base64 string) arrives pretty instantly, yet it takes about 12 - 15 seconds for the image to appear in the ImageView.
I find this very strange because I used an NSStream to get the data for the image in a different method and the image loaded as soon as all the data arrived. But with this URLSession method its taking longer for the image to load. This doesn't really make sense! This method shouldn't affect how the ImageView loads that data.
Has anybody any ideas why this might be happening?
heres the code:
- (void)postMethod:(NSDictionary *)numDict
{
NSURL *url = [NSURL URLWithString:#"http://theWebAddress.com/aPage.php"]; // add url to page
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = #"POST";
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:numDict options:kNilOptions error:&error];
NSLog(#"%#", numDict);
if (!error)
{
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *diction = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
for (id key in diction)
{
if ([key isEqualToString:#"text"])
{
NSLog(#"data is text");
self.messageLabel.text = diction[#"text"];
break;
}
else if ([key isEqualToString:#"image"])
{
NSLog(#"data is an image");
// gets the base64 string pretty instantly but takes 12 - 15 seconds to pop up in the imageView
NSData *ImgData = [[NSData alloc] init];
ImgData = [[NSData alloc] initWithBase64EncodedString:diction[#"image"] options:1];
self.ImageView.image = [UIImage imageWithData:ImgData];
break;
}
}
}];
[uploadTask resume];
}
}
many thanks!
Your completion handler might be operating on a background thread. UI updates should always work on the main thread. Put a break point at
self.ImageView.image = [UIImage imageWithData:ImgData];
and see if it is on the main thread. If not, dispatch it to the main thread before you set the ImageView.image:
dispatch_async(dispatch_get_main_queue(), ^{
self.ImageView.image = [UIImage imageWithData:ImgData];
});
You can try to use SDWebImage https://github.com/rs/SDWebImage and all you need is to set the image in imageView like this:
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
You are firstly downloading image and then showing image.You can download image by using lazy loading.
For this you can use EgoImageView not uiimageview.
self.ImageView.imageURL=[NSURL URLWithString:
here self.ImageView is of egoimageview type.
you can get this class from github.
https://github.com/enormego/EGOImageLoading
I have to make som changes to a iPhone app...
How can i change the background on a UIViewController on load (viewDidLoad) .. I have to show a .png from a URL .. Is that posible?
I have tried:
NSURL *url = [NSURL URLWithString:#"http://url_to_my_project/xmas-bg-test.png"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
this is from my : "- (void)viewDidLoad" method .. Nothing happend when I start my app.. no errors ether.
I have also tried from my .. viewDidAppear
You have to create UIImageView as a background image. Remove self.view.backgroundColor = ... line and add this:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = self.view.frame;
[self.view addSubview:imageView];
[self.view sendSubviewToBack:imageView];
in viewDidLoad: method.
That's not how you add a background to a view controller. Add a new UIImageView ivar to your view controller subclass and use that.
- (void)viewDidLoad {
...
imageView.image = [UIImage imageWithData:data];
}
You have to make sure you create this image view properly. Either by adding an image view in Interface Builder and linking it to your imageView ivar, or by creating it yourself in awakeFromNib or loadView.
The other answers are correct for saying that you should be using an image view to display the image. However, you should consider making a request for the image. This way, if the request fails you can handle it by displaying a different image or what ever you want. Here's a rough example.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://url_to_my_project/xmas-bg-test.png"] cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:5.0];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (response && !error) {
UIImage *image = [UIImage imageWithData:data];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[imageView setImage:image];
[self.view addSubview:imageView];
}
}];