What i need is to wait till setImageWithURL has finished proccesing the image, here is my code on the viewDidLoad method:
UIImageView *test = [[UIImageView alloc] init];
[test setImageWithURL:[NSURL URLWithString:object.imageUrl]];
Is there anyway to set this method to run synchronous? I have tried the completed block, but for some strange reason it never gets called.
From what I remember SDWebImage doesn't have methods to download/set image synchronously (for obvious reasons). But if your use case wants you to use a synchronous method, try this:
UIImageView *test = [[UIImageView alloc] init];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
[test setImage:image];
Hope this helps.
Related
i am sending a PFImageView*(Parse.com subclass of UIImageView)* to a new View, where i am adding it as a subview, this ofc leads to the PFImageView getting detached from its previous view, which id like to avoid.
I have to call Copy, and CopyWithZone on the PFImageView, but the class does not seem to support that method, i have also tried the following:
UIImage *copiedImage = [[UIImage alloc] initWithCGImage:[[sender image] CGImage]];
PFImageView *copiedImageView = [[PFImageView alloc] initWithImage:copiedImage];
[segue.destinationViewController setFullSizeImage:copiedImageView];
But this leads to an empty PFImageView? Can i add a category to PFImageView and implement the CopyWithZone protocol ? And if so, how would i implement it?
fixed it by implementing a category with the following:
-(id)copyPFImageView
{
PFImageView *copy = [[PFImageView alloc] init];
[copy setFile:[self file]];
[copy setImage:[self image]];
return copy;
}
Remember that the data in file is quite essential
For some reason when I'm downloading my image using GCD, the image will randomly start flickering.
I'll reset the content settings in simulator and it'll work once, then it'll just start flickering again.
This is the code I am using. I've got the reloads in there because if I don't reload it, the image doesn't show until I tap on the cell.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
NSData *imgData = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
cell.imageView.image = nil;
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
[self.tableView reloadData];
});
});
return cell;
[self.tableView reloadData];
That's because you are using dispatch_async(dispatch_get_global_queue to async load imageData from file. Using this style load image in cellForRow will make cell image should should previous image first. Then finish async load, will call dispatch_sync(dispatch_get_main_queue(), to load the image you want to. Therefore, whenever you reloadData or any other methods to call cellForRow, the cell image will flicker.
I know you want to load image without blocking main thread, but it's not a good way.
Check out apple sample code for Lazy Image loading. And also I checked your code and found that you always downloading image from URL. Instead of that its good to download and save image in caches and then load image from next time in cellForRowAtIndexPath method from local caches if available.
Is this code in cellForRowAtIndexPath:?
If that is the case, the problem here is that all the cells are infinitely reloading the table. You should not be calling reloadData in any of datasource methods that are triggered by reloadData.
What you have is basically an infinite loop of reloading. (reloadData triggers cellForRowAtIndexPath: which once again triggers reloadData).
My suggestion is to use an external component for this as aeskreis posted in his comment.
SDWebImage is probably the best one out there and will allow you to simplify all of the code you have there into simply:
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
[cell.imageView setImageWithURL:url];
Okay Guys I found out the problem. It was constantly reloading the data which caused te flickering. instead of [self.tableView reloadData] I replaced it with this method:
[cell setNeedsLayout];
I believe this method detects if anything has been changed, and then updates it (from my memory of a couple hours ago so it's probably not 100% accurate), but that fixed my problem.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
NSData *imgData = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
//[self.tableView reloadData];
[cell setNeedsLayout];
});
});
return cell;
I am trying to call a method in which I send to the background making use of dispatch_async.
It should be something that is simple, but for some reasons the UI is still blocked until the method returns.
Here is what I have:
dispatch_queue_t privateQueue = dispatch_queue_create("com", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(privateQueue, ^
{
__block UIImageView *imgView = [[UIImageView alloc] initWithFrame:self.view.frame];
dispatch_async(dispatch_get_main_queue(), ^
{
imgView = [controllerB startProcess];
controllerC.imageView = imgView;
});
});
I still have to wait for startProcess returns before UI is free again.
Then I tried to move imgView = [controllerB startProcess]; outside of dispatch_get_main_queue():
dispatch_async(privateQueue, ^
{
__block UIImageView *imgView = [[UIImageView alloc] initWithFrame:self.view.frame];
imgView = [controllerB startProcess];
dispatch_async(dispatch_get_main_queue(), ^
{
controllerC.imageView = imgView;
});
});
In this case, the UI is never updated with imgView but UI is not locked up.
I have tried to use a global queue, but the result is the same (UI has to wait):
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
I think I am missing something very obvious here. Either that or it has been long day for me.
EDIT:
In [controllerB startProcess];
I am making use of:
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I am not sure if these methods have anything to do with GCD that causes my problem. The image is just .png.
Been thinking hard on this. Am running out of ideas. The only way I can update the UI with the image is to place the method call within dispatch_get_main_queue(), which beats the purpose of using GCD because all UI is blocked until the image is ready and method returns.
Any suggestion would be greatly greatly appreciated.
Use the second approach. Modify startProcess to use completion blocks and update your imageView inside the completion block. This ensures that imageView is updated after startProcess is complete.
Is it possible, that -in your 2nd example- when you try to set the imageView on the main queue the asynchronous calculation of the imageView in the background has not finished yet, so it can't display the imageView?
In that case a dispatch group might help:
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("com.name.queueā€¯, DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
//Do work
imgView = [controllerB startProcess];
});
dispatch_group_notify(group,queue,^{
//This code runs as soon as the code in the dispatch group is done.
controllerC.imageView = imgView;
});
In my app I just implement a dispatch_async block that will grab images from a NSDictionary and then eventually when the image is ready, set it to a UITableViewCell UIImageView. What I want to do is make a UIActivityIndicatorAppear in the middle of the UITableViewCell's UIImageView while the dispatch_async is occurring.
This is my code for the dispatch_async block:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(void) {
NSData *data = [myDictionary objectForKey:#"myKey"];
UIImage *cellImage = [UIImage imageWithData:data];
//we get the main thread because drawing must be done in the main thread always
dispatch_async(dispatch_get_main_queue(),^ {
[cell.imageView setImage:cellImage];
} );
});
Anyway is this possible? And if so, how?
Thanks!
Show the progress indicator before your dispatch_async and remove or hide it your main queue block where you set the image.
I have this code:
imageNumber++;
UIImage *image = [[UIImage alloc]init];
image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image]; //<-- here it crash
[image release];
so, after a few minuted my app crash with this message
[UIImage isKindOfClass:]: message sent to deallocated instance
why?? can you help me?
imageNumber++;
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image];
The problem with your code is that you allocate a UIImage object on image variable and then without releasing it you set it to another autoreleased object. [UIImage imageNamed:] returns an autoreleased UIImage object.
You are allocating a new image, and then you are assigning that pointer to an autoreleased UIImage returned by UIImage imageNamed:, causing a memory leak, then you try to release an autoreleased object, which get released again, causing the error.
imageNumber++;
image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image]; //<-- here it crash
it seems like you got it all wrong. At first you alloc-init object and then assign autorelased object to the pointer, making the first object leaking. Here is the correct code:
imageNumber++;
UIImage *image [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image];
1) You don't need to allocate an empty image before loading the image from a file.
2) Are you sure that the image specified by the string [NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber] actually exists and is available to the app ?
the imageNamed call will return null if that image cannot be found. Step through in the debugger and see if the image is actually loaded.