Images hangs and takes too long to populate from service - ios

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

Related

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) block doesn't execute

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
}
];

get image faster than file URL

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];
});
});

How can get any message if Image View can't get image from given URL?

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];
}
});

iOS app closes unexpectedly

I have a problem with my iOS app I cannot solve. It keeps quitting and sometimes the whole iPhone restarts when there are other apps open (even background ones).
When looking with the profiling tools provided with xCode it seems that “ImageIO_JPEG_Data” uses all the ram available.
I attach you the images from the profiler. If you need anything else please let me know!!
EDIT: found it! That’s the code causing it
-(void)downloadFromURL:(NSString *)url withPlaceholder:(UIImage *)placehold
{
if (placehold) {
[self setImage:placehold];
}
if (url) {
if ([url rangeOfString:#"/Library/"].location != NSNotFound) {
NSData *imageData=[NSData dataWithContentsOfFile:url];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
[self setImage:image];
[self setNeedsLayout];
}
return;
}
NSString *strImgName = [[[[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] componentsSeparatedByString:#"/"] lastObject] retain];
AppDelegate *app=[[UIApplication sharedApplication]delegate];
[app applicationCacheDirectoryString];
// NSString *imagePath = [NSString stringWithFormat:#"%#%#",[[AppDelegate sharedObject]applicationCacheDirectoryString],strImgName];
NSString *imagePath = [NSString stringWithFormat:#"%#%#",[app applicationCacheDirectoryString],strImgName];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *aURL=[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if ([fileManager fileExistsAtPath:imagePath]==NO)
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:aURL]];
[imageData writeToFile:imagePath atomically:YES];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:image];
[self setNeedsLayout];
});
}
});
}
else{
NSData *imageData=[NSData dataWithContentsOfFile:imagePath];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
[self setImage:image];
[self setNeedsLayout];
}
}
}
}
Apparently it wasn’t a bug in my code causing it, somehow the sqlite database I was using got corrupted and removing the app and reinstalling it seems to have fixed it.

NSData dataWithContentsOfURL for twitter picture returning nil when same thing works for instagram

Im trying to display twitter pictures but dataWithContentsOfString is returning nil when the same exact thing works for an instagram photo url. It works when I use the actual url instead of getting it from the nsdictionary
NSString *twitterString = #"http://pbs.twimg.com/media/BYWHiq1IYAAwSCR.jpg"
but not like this
if ([post valueForKeyPath:#"entities.media.media_url"]) {
NSString *twitterString = [NSString stringWithFormat:#"%#", [post valueForKeyPath:#"entities.media.media_url"]];
NSURL *twitterPhotoUrl = [NSURL URLWithString:twitterString];
dispatch_queue_t queue = kBgQueue;
dispatch_async(queue, ^{
NSData* data = [NSData dataWithContentsOfURL:twitterPhotoUrl];
UIImage *image = [UIImage imageWithData:data];
dispatch_sync(dispatch_get_main_queue(), ^{
[streamPhotoArray replaceObjectAtIndex:indexPath.row withObject:image];
cell.twitterPhoto.image = image;
});
});
}

Resources