Load image using imageWithContentsOfFile + GCD in table still slower than SDWebImage - objective-c

I have been using SDWebImage's setImageWithURL... to load remote images on tableview. It is perfect.
Now I need to create a table of user saved images but since images are not remote, I cant use SDWebImage. Besides images are saved by user using [imageData writeToFile..] so I cant use imageNamed either.
I tried to use GCD (this code is part of a UIImageView+ category..):
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
dispatch_sync(dispatch_get_main_queue(), ^{
[self setImage:image];
[self setNeedsLayout];
});
});
It still feels much slower than a table of remote images managed by SDWebImage. Is there any way to handle cache/asynchronous loading of LOCAL images?

Related

iOS use cached image with SDWebImage properly

I am using SDWebImage to get pictures.
let's say I have two view controllers A and B. B is the next view of A. they need to show the same image:
[iconIamgeView setImageWithURL:[NSURL URLWithString:#"http://www.example.com/icon.jpg"];
I thought SDWebImage would cache http://www.example.com/icon.jpg after this code in A, so B was going to use the cache. Thus there should not be a detectable latency when I used this code to show the same image in B. However, it seems that I was wrong. there was an obvious latency when I wanted to show this image in B.
How can I use the cache properly? thanks!
I am sorry that the problem I mentioned in the question was not the real problem.
[iconIamgeView setImageWithURL:[NSURL URLWithString:#"http://www.example.com/icon.jpg"];
this code does the cache work well.
the real problem is my code of setting image was not on the main thread, so I could not show the image immediately. I used dispatch_async to solve the problem:
dispatch_async(dispatch_get_main_queue(), ^{
[iconIamgeView setImageWithURL:[NSURLURLWithString:#"http://www.example.com/icon.jpg"];
});
hope this answer may help someone who faces the same issue.
NSURL *imageURL = [NSURL URLWithString:[linkImageArray objectAtIndex:index]];
UIImage *placeholderImage = [UIImage imageNamed : [linkImageArray objectAtIndex: index]];
[imageView setImageWithURL:imageURL
placeholderImage:placeholderImage
options:SDWebImageRefreshCached
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType)
{
NSLog(#"image loaded");
}];

Get image Asynchronously and setting setNeedsDisplay

This code is in in a cell initialization routine that sets up the elements of a custom cell. It gets the image from the web asynchronously. But I need it to redraw once it's done.
This is my snippet of code:
dispatch_async(myCustomQueue, ^{
//Look for the image in a repository, if it's not there
//load the image from the web (a slow process) and return it
mCover.image = [helperMethods imageManagerRequest:URL];
//Set the image to be redrawn in the next draw cycle
dispatch_async(dispatch_get_main_queue(), ^{
[mCover setNeedsDisplay];
});
});
But it doesn't redraw the UIImageView. I've tried to also redraw the entire cell, and that doesn't work either. Your help is much appreciated. I've been trying to fix this for some time!
Instead of setNeedsDisplay, you should set the image on main thread as Apple have mentioned in their documentation.
Note: For the most part, UIKit classes should be used only from an
application’s main thread. This is particularly true for classes
derived from UIResponder or that involve manipulating your
application’s user interface in any way.
This should fix your problem:
dispatch_async(myCustomQueue, ^{
//Look for the image in a repository, if it's not there
//load the image from the web (a slow process) and return it
UIImage *image = [helperMethods imageManagerRequest:URL];
//Set the image to be redrawn in the next draw cycle
dispatch_async(dispatch_get_main_queue(), ^{
mCover.image = image;
});
});

How to efficiently read multiple images from documents directory in iOS

I am working on an app that saves multiple images in Documents directory. These images can be up to 100. Now use following method to read the image from Documents directory. This method is called for all images in Documents directory.
UIImage *currentImage = [UIImage imageWithContentsOfFile:pathOfFileInDocumentsDictory];
So in worse case this method will run for 100 images and I have checked using XCode that this method takes around 100 miliseconds. So this makes 10 seconds for 100 images if I am not wrong. I want to make it efficient. Is there any better way to read those image for efficiently and in less time?
Using run loops, you could do this:
-(void) loadInBackground {
[self performSelectorInBackground:#selector(_loadInBackground) withObject:nil];
}
-(void) _loadInBackground {
// Do all your heavy loading here
UIImage *currentImage = [UIImage imageWithContentsOfFile:pathOfFileInDocumentsDictory];
[self performSelectorOnMainThread:#selector(loadedImage:) withObject:currentImage waitUntilDone:YES];
}
-(void) loadedImage:(UIImage*)img {
// Do something with the loaded image
anImageView.image = img;
}

Cache NSData(with UIImages)

Currently, I'm working on the client for the website. I have tonne of images that I need to load to my TableView. Here is what I'm currectly doing:
NSDictionary *propertyItems = [self.items objectAtIndex:indexPath.row];
cell.fio.font = [UIFont boldSystemFontOfSize:17.0f];
if([propertyItems objectForKey:#"online"] == [NSNumber numberWithInt:1])
cell.fio.textColor = [UIColor colorWithRed:0.3 green:0.6 blue:0.3 alpha:1.0];
dispatch_queue_t downloadPhotosQueue = dispatch_queue_create("downloadPhotosQeue", NULL);
dispatch_async(downloadPhotosQueue, ^{
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.pic.image = [UIImage imageWithData:photosData];
});
});
cell.fio.text = [propertyItems objectForKey:#"fio"];
I'm doing this in cellForRowAtIndexPath: method.
Everything is loading fast. But the problem is, when I'm scrolling my table down, and after again up, the images are reloading over and over again.
Question: Is there any way to easily cache my UIImages that I'm getting from the server? So if they are loaded once, they wouldn't reload over and over again, while I'm running the app. Maybe I'm doing something wrong?
Thanks in advance!
I strongly recommend AsyncImageView. I use it and it works like a charm. Just set the image url and it handles everything itself.
AsyncImageView *imageView = [[AsyncImageView alloc]init];
imageView.imageURL = [NSURL URLWithString:#"https://www.google.es/logos/classicplus.png"];
It caches the image in memory so it won't retrieve it from the server again. It will also release them when receiving a memory warning.
To load image from a website I use AFNetworking. It provides a class to load an image from an URL:
Start by adding #import "UIImageView+AFNetworking" to the top of a
controller or a view implementation file. This category adds methods
to UIImageView, like:
[imageView setImageWithURL:[NSURL URLWithString:#"…"]];
i recommend this library to accomplish what you want.
in cellForRowAtIndexPath:
[cell.imageView setImageWithURL:
[NSURL URLWithString:[NSString stringWithString:#"www.yourimagepath.path"]]
placeholderImage:[UIImage imageNamed:#"no_image.jpg"]];
the library will cache the image for you. you can also set the setHolder of the image, so it wont look like a blank image while the images are downloading.
The problem is here :
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dataWithContentsOfURL
It launch a request to the Url everytime the function is called (everytime you scrolled).
You need to load all the picture before cellForRowAtIndexPath.
Like in ViewDidLoad.
You can just store them in an array and display your picture's array in cellForRowAtIndexPath.
If it's really fast to load like you say : jsut load picture Once in CellForRowAtIndexPath. Store them in a mutableArray. And check if the picture already exist .

Problems to create a Thumbnailimage from a WORD document in Objective c

I'm trying to create a ThumbnailImage to Word document. I use a UIWebView to load the document and then transform it into an image. Png. I've watched a thousand times and the file path is correct, but the final image is blank. Someone can look at my code to see if there is something wrong?. Thank you very much in advance.
UIWebView *myWebView22 = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
path44 = [caminoINICIAL stringByAppendingPathComponent:#"documentoInicial.doc"];
NSURL *fileURL22 = [[NSURL alloc] initFileURLWithPath:path44];
NSURLRequest *req22 = [NSURLRequest requestWithURL:fileURL22];
[myWebView22 setScalesPageToFit:YES];
[myWebView22 loadRequest:req22];
UIGraphicsBeginImageContext(myWebView22.bounds.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(c, 0, 0);
[myWebView22.layer renderInContext:c];
UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
pngPath = [caminoINICIAL stringByAppendingPathComponent:[NSString stringWithFormat:#"imagenFinal.png"]];
[UIImagePNGRepresentation(viewImage) writeToFile:pngPath atomically:YES];
I'm pretty sure that's a timing problem. UIWebView has is own threads and loads the document async, you need to wait until it's loaded before you use renderInContext.
Figuring out the time might be tricky, either with a fixed time or some deep-subview-inspection.
You might wanna use QuickLook instead of UIWebView to get a little bit more control about the rendering.
The problem is that you are firing the request then immediately capturing the image. loadRequest: is asynchronous. It sends the request, and returns immediately. It doesn't wait until the document has loaded before returning. So when you capture the image, the device is still busy loading the document.
You can provide a delegate to the web view that receives a message once the document has finished loading. Capture the image from within that delegate method.