the following code is working just fine:
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue,
^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
[self performSelectorOnMainThread:#selector(setImage:)
withObject:[UIImage imageWithData:imageData] waitUntilDone:NO];
});
since I need to call it from different viewControllers I want place it in a general class that has public global help function (+) so I'm looking for a way to pass the selector and the target as parameters for performSelectorOnMainThread to run with
You implied that you have the target. Why don't you just call it with the target?
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue, ^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
[target performSelectorOnMainThread:#selector(setImage:)
withObject:[UIImage imageWithData:imageData]
waitUntilDone:NO];
});
Or better
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue, ^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
dispatch_async(dispatch_get_main_queue(), ^{
[target setImage:[UIImage imageWithData:imageData]];
});
});
Related
I am trying to fetch images on a button click in Viewcontroller B .After the image is received as response,I use the url of images to populate the imageviews on viewcontroller.But,it is taking too long to get populated and also hangs while scrolling.Is there any way to scroll the view smoothly without freezing and get the response little early.
This line should not be in main queue
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[responseArr objectAtIndex:indexPath.row]valueForKey:#"CategoryImage"]]];
you may change to something like this
NSString *getImagePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.jpeg",n1.Id]];
if([[NSFileManager defaultManager] fileExistsAtPath:getImagePath])
{
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
cell.leftImageV.image =img;
[cell.activity stopAnimating];
cell.activity.hidden=YES;
}
else
{
[cell.activity startAnimating];
cell.activity.hidden=NO;
cell.leftImageV.image = nil;
NSLog(#"xdasdxsadxa %#",n1.mainImgStr);
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block NSData * imageData = nil;
dispatch_sync(concurrentQueue, ^{
imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:n1.mainImgStr]];
//Add the file name
[imageData writeToFile:getImagePath atomically:YES]; //Write the file
});
dispatch_sync(dispatch_get_main_queue(), ^{
if(imageData)
{
[self.collectionView reloadData];
}
});
});
}
Use dispatch async for image retrieve, namely, don't do it on main queue.
Apple Doc:
https://developer.apple.com/documentation/dispatch/1453057-dispatch_async
I have a block to download an convert an image to UIImage. this is my code
-(UIImage *)GetProfileImage
{
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
__block UIImage *imgProf=nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
imgProf= image;
if(image!=nil){
imgProf=image;
}
});
});
return imgProf;
}
But this block is never execute.It goes to return __block UIImage *imgProf=nil; Why is that? Please help me.
Thanks
Code is working ok. This is the purpose of dispatch_async.
Form the documentation
#function dispatch_async
Calls to dispatch_async() always return immediately after the block has been submitted, and never wait for the block to be
invoked.
This is the opposite of dispatch_sync.
You could change the GetProfileImage like this
- (void)setProfileImageForImageView:(UIImageView *)imageView {
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
__block UIImage *imgProf=nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
imgProf= image;
if(image!=nil){
// imgProf=image;
imageView.image = image;
}
});
});
}
Use a completion block instead, rather than returning from function:
-(void)GetProfileImageWithCompletion:(void (^)(UIImage *profileImage))completionHandler
{
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
if(image!=nil && completionHandler){
completionHandler(image);
}
});
});
}
And use like this:
[self GetProfileImageWithCompletion:^(UIImage *profileImage)
{
//if image exists assign to image view
}
];
I'm creating a stack of images in my viewdidload method. The images are from PFFile's from parse so they contain the fileURL of my image data.
My problem is that these two lines of code are dramatically slowing down my app and killing my user experience:
//get scene object
PFObject *sceneObject = self.scenes[i];
//get the PFFile and filetype
PFFile *file = [sceneObject objectForKey:#"file"];
NSString *fileType = [sceneObject objectForKey:#"fileType"];
//check the filetype
if ([fileType isEqual: #"image"])
{
//get image
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl]; ********** these
imageView.image = [UIImage imageWithData:imageData]; ********************* lines
}
How do I get this image/these images (this is nested in a for loop) more quickly? I've already downloaded my PFObjects that contain the PFFiles and stored them locally.
I guess I really don't understand how file URL's operate.
Thank you.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
Have not tested but this is the gist. Get the file loading off the main queue and make it asynchronous. The UI will not be bogged down because as soon as this queue is dispatched it's going to return and keep evaluating the rest of your application.
I am using somethig like this:
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[imageFrame addSubview:activityIndicator];
activityIndicator.center = CGPointMake(imageFrame.frame.size.width / 2, imageFrame.frame.size.height / 2);
[activityIndicator startAnimating];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumb]];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
img.image = image;
[imageOver addSubview:img];
[activityIndicator removeFromSuperview];
});
});
I am fetching URL from web, and I want to show any message if image view can't get image from given URL.
Here is my Code.
NSString * image1 = [WebArray objectForKey:#"image_url"];
NSString * image2 = [[tempArray objectAtIndex:0]objectForKey:#"user_image"];
dispatch_queue_t imageQueue = dispatch_queue_create("Image Queue", NULL);
dispatch_async(imageQueue, ^{
NSURL *url = [NSURL URLWithString:image1];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
NSURL *url1 = [NSURL URLWithString:image2];
NSData *imageData1 = [NSData dataWithContentsOfURL:url1];
UIImage *image11 = [UIImage imageWithData:imageData1];
dispatch_async(dispatch_get_main_queue(), ^{
[user_image setImage:image];
[self.tag_user_img setImage:image11];
});
});
check image view is empty or not using
if(CGSizeEqualToSize(imageView.image.size, CGSizeZero))
{
show alert here....
}
dispatch_async(dispatch_get_main_queue(), ^{
if(!image)
{
// show your message
}
else
{
[user_image setImage:image];
}
});
In my app, Im using an API to get images from a server. Using the below code, it gets the images in order of size to replace themselves with better quality.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"normal"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
self.shotImage = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"hidpi"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
Also, if you press on the image it then takes you too another ViewController where the image is fullscreen.
However, even if I wait for the high quality one to load before I tap on it, in the PrepareForSegue Method, it still only passes the original low quality version.
See code below from PrepareForSegue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
FullSizeImageViewController *vc = [segue destinationViewController];
UIImage *img = [[UIImage alloc] init];
img = self.shotImage;
vc.shotImage = img;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"hidpi"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
In this code looks like you miss this line:
self.shotImage = [UIImage imageWithData:imageData];