Issue with setImageWithURL AFNetworking success handler - ios

Neither the success or failure handler appears to be called when setImageWithURLRequest: is called on my UIImage object. SetImageWithURL does not set my image either. If I use setImageWithURL: placeholder: the placeholder is set but the image from the url never gets set.
Pardon my not posting code sooner. I have tried to use two methods (with AFNetworking) to asynchronously set my image views:
[_imageView setImageWithURL:[NSURL URLWithString:#"path/to/file"]];
[_imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.example.com/path/to/image.jpg"]] placeholderImage:[UIImage imageNamed:#"your_image_here.jpg"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(#"Your image request succeeded!");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Your image request failed...");
}];
I have tried having these triggered in viewDidLoad but the image view never loads.
After looking through the actual function declaration of setImageWithURLRequest: and it appears that neither the success or failure block is executed when I call it. I've placed NSLogs in the code to give you guys an idea of what happens:
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
{
NSLog(#"Log shows");
[self cancelImageRequestOperation];
NSLog(#"Log shows");
UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest];
NSLog(#"Log shows");
if (cachedImage) {
NSLog(#"Log does not show");
self.image = cachedImage;
self.af_imageRequestOperation = nil;
if (success) {
success(nil, nil, cachedImage);
NSLog(#"Log does not show");
}
} else {
NSLog(#"Log shows");
self.image = placeholderImage;
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
self.image = responseObject;
self.af_imageRequestOperation = nil;
NSLog(#"Log does not show");
}
if (success) {
success(operation.request, operation.response, responseObject);
NSLog(#"Log does not show");
}
[[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
self.af_imageRequestOperation = nil;
NSLog(#"Log does not show");
}
if (failure) {
failure(operation.request, operation.response, error);
NSLog(#"Log does not show");
}
}];
self.af_imageRequestOperation = requestOperation;
[[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation];

setImageWithURL: is a UIImageView category and cannot be used for setting a UIImage only used on a UIImageView.
[imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeHolderImage"]];
Here's the documentation: http://engineering.gowalla.com/AFNetworking/Categories/UIImageView(AFNetworking).html

Thanks for the help guys but like everyone on here noticed, there was no issue with my code. The issue was actually with regard to ARC. I had it turned off in my AFNetworking files. After turning it on, everything worked just fine.

Related

AFNetworking setting an UITableViewCell's imageView image with URL, imageview frame is still 0 after setting image

This is from the UIImageView+AFNetworking library.
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[urlRequest URL] isEqual:[[self.af_imageRequestOperation request] URL]]) {
if (success) {
success(operation.request, operation.response, responseObject);
} else {
self.image = responseObject;
[self setNeedsLayout];
[self setNeedsDisplay];
}
self.af_imageRequestOperation = nil;
}
I added in setNeedsLayout and setNeedsDisplay. The imageview, a UITableViewCell 's imageView in this case, still has a 0,0,0,0 frame. Clicking on the cell will refresh the imageview but otherwise the image does not show up.
How do I force the UIImageView to resize?
I tried putting in
self.image = responseObject;
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y,
self.image.size.width, self.image.size.height);
[self setNeedsDisplay];
[self setNeedsLayout];
based on
How to make UIImageView automatically resize to the size of the image loaded
's solution of setting the frame. I can log out a bigger frame there but it does not show up on screen.
Its hard to tell without seeing the rest of your code, but I believe the problem might be in your completion handler for the request operation:
if (success) {
success(operation.request, operation.response, responseObject);
} else {
self.image = responseObject;
[self setNeedsLayout];
[self setNeedsDisplay];
}
You seem to set the image only when the request failed. Moving it to the success block might fix it.
if (success) {
success(operation.request, operation.response, responseObject);
self.image = responseObject;
[self setNeedsLayout];
[self setNeedsDisplay];
}
Is there a particular reason why you are not using AFNetworking/UIImageView+AFNetworking.h methods? Seems like they would fit your use-case.
- (void)setImageWithURL:(NSURL *)url
placeholderImage:(nullable UIImage *)placeholderImage;
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;

AFNetworking setImageWithURLRequest not updating UIImageView

I am downloading an image from a URL using setImageWithURLRequest:placeholderImage:success:failure and the download of the image works correctly. The issue I am having is that when I set the downloaded image to the UIIMageView nothing shows but the placeholder is removed.
My code is as follows:
__weak UIImageView *userCardImageView;
AFImageResponseSerializer *serializer = [[AFImageResponseSerializer alloc] init];
serializer.acceptableContentTypes = [serializer.acceptableContentTypes setByAddingObject:#"image/png"];
self.userCardImageView.imageResponseSerializer = serializer;
[self.userCardImageView setImageWithURLRequest:urlRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[userCardImageView setImage:image];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
if (error)
{
NSLog(#"Error: %#", error);
NSLog(#"Error response: %#", response);
}
}];
The URL is correct as when I copy and past it into a browser I get my image.
Can someone advise me how I can get my code to work to update the URL? Am I right to assign the UIImageView to a weak property? I am doing this as using self or a strong variable could lead to a retain cycle.
It seems that you should implement the line
[userCardImageView setImage:image];
instead of
[userCardImageView setImage:[UIImage imageWithData:userCardImageData]];
in your success block
PS: If it is the self.userCardImageView which you want to set the image in, you would rather declare a weak controller instead of a weak UIImageView reference. Something like
__weak __typeof(&*self)weakSelf = self
Actually you are not assigning the downloaded image to image view correctly.[userCardImageView setImage:[UIImage imageWithData:userCardImageData]];, we need not to assign the image from this variable userCardImageData, try this code
[self.userCardImageView setImageWithURLRequest:urlRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
[userCardImageView setImage:image]; //set image in main thread , we got downloaded image as parameter in block
});
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
if (error)
{
NSLog(#"Error: %#", error);
NSLog(#"Error response: %#", response);
}
}];
Hope this helps
Should be enough just:
[self.userCardImageView setImageWithURL:url];

setImageWithURLRequest:placeholderImage:success:failure No block is called

I'm trying to get an image asynchronously from an url with AFNetworking 2.0
My problem is that neither success nor failure are called
I've checked my URL in a browser so the problem is not here
UIImageView *imgv = [[UIImageView alloc] init];
[imgv setImageWithURLRequest:myURL
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
/*some code*/
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
/*some code*/
];
When I look deeper inside setImageWithUrlRequest:placeholderImage:success:failure
__weak __typeof(self)weakSelf = self;
self.af_imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
self.af_imageRequestOperation.responseSerializer = self.imageResponseSerializer;
[self.af_imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (success) {
success(urlRequest, operation.response, responseObject);
} else if (responseObject) {
strongSelf.image = responseObject;
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
[[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (failure) {
failure(urlRequest, operation.response, error);
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
}];
My code goes trought [self.af_imageRequestOperation setCompletionBlockWithSuccess:^( AFHTTPRequestOperation *operation, id responseObject) {
with success but i've noticed that __strong __typeof(weakSelf)strongSelf = weakSelf; are both nil
Any idea?
Your imgv is never retained so it will be released after current scope so in your block weakSelf will be release when image is successfuly downloaded so thats why you are getting nil.

How to tell if blocks in loop all have completed executing?

I have a loop set up that downloads a series a images which I will later use for to animate using the animationImages property of UIImageView. I would like to know when all the blocks inside my loops have finished executing so I could begin the animation, and was wondering how I may be able to tell when they are finished completing? Thanks!
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
}];
}
//When I know all the blocks have finished downloading, I will then to animate the downloaded images.
Edit: having issue with Error -999
I am encountering the following issue when executing the code in the provided answer: Domain=NSURLErrorDomain Code=-999 "The operation couldn’t be completed. (NSURLErrorDomain error -999.)"
A quick search reveals that Error -999 means "another request is made before the previous request is completed" ... which is certainly the case here since I am making several requests in quick succession. The recommended fix suggested here didn't work for me as it will only successfully download one UIImage (the last one requested) , with the previous ones failing. I was wondering if there is workaround here or in AFNetworking that I ought to consider? Thanks!
Edit 2: working code based on #David's solution
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:imageRequest];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
dispatch_group_enter(group);
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", responseObject);
UIImage *retrivedImage = (UIImage *)responseObject;
[self.downloadedUIImages addObject:retrivedImage];
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Image error: %#", error);
dispatch_group_leave(group);
}];
[requestOperation start];
counter ++;
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"Horray everything has completed");
NSLog(#"What is here %#", self.downloadedUIImages);
NSLog(#"Done");
});
Create a dispatch group, in the for loop enter the group, in the completion block leave the group. Then you can use dispatch_group_notify to find out when all blocks have completed:
dispatch_group_t group = dispatch_group_create();
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
dispatch_group_enter(group);
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
dispatch_group_leave(group);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// do your completion stuff here
});
Count how many you've completed. The challenging part is making it thread safe. I recommend creating an atomic counter class for that.
Generic solution!
+ (void)runBlocksInParallel:(NSArray *)blocks completion:(CompletionBlock)completion {
AtomicCounter *completionCounter = [[AtomicCounter alloc] initWithValue:blocks.count];
for (AsyncBlock block in blocks) {
block(^{
if ([completionCounter decrementAndGet] == 0) {
if (completion) completion();
}
});
}
if (blocks.count == 0) {
if (completion) completion();
}
}
NSMutableArray *asyncBlocks = [NSMutableArray array];
for (PFObject *pictureObject in objects){
[asyncBlocks addObject:^(CompletionBlock completion) {
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
} completion:completion];
}];
}
[BlockRunner runBlocksInParallel:[asyncBlocks copy] completion:^{
//Do your final completion here!
}];
Set up a property and initialize it to the number of cycles - objects.count. In the completion of the block, lower the number down. When you reach zero, you are done.
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
}];
}
- (void)animateImages {
//do animation here.
}

AFNetworing - setImageWithURLRequest not working

I want to set tableview cell images in one of my apps. I use AFNetworking (1.2.1) and I do it with setImageWithURLRequest.
My code in which I set images looks like this:
if (user.avatar) {
NSString *imageUrl = user.avatar.url;
[cell.profileImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[cell setNeedsLayout];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
My error log returns this:
Error: Error Domain=NSURLErrorDomain Code=-999 "The operation couldn’t be completed. (NSURLErrorDomain error -999.)" UserInfo=0x1f5b56a0 {NSErrorFailingURLKey=https://d2rfichhc2fb9n.cloudfront.net/image/5/Cf7T_BA6- NFGL5ah0w4hdvmk_Vp7InMiOiJzMyIsImIiOiJhZG4tdXNlci1hc3NldHMiLCJrIjoiYXNzZXRzL3VzZXIvZTIvM2MvMjA vZTIzYzIwMDAwMDAwMDAwMC5qcGciLCJvIjoiIn0}
And the images dosn't get set. I didn't have this problem before I updated to AFNetworking (1.2.1). Any ideas?
Update
Tried to strip the whitespace from the url like this:
NSString *imageUrl = [user.avatar.url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
But I get the same error. And it could maybe be dangerous if the API sometime would contain a image file name that contains whitespaces.
I see three problems:
-999 means NSURLErrorCancelled, so it looks like the URLRequest gets cancelled somehow. Where is this code of yours? Is it possible that the cell object or the UIImageView profileImage is released prematurely?
More recent versions of AFNetworking require you to set the image yourself if you're defining a success block.
Make sure the URL is valid.
Try this (works when placed in tableView:cellForRowAtIndexPath:):
__weak UITableViewCell *weakCell = cell;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
if (weakCell)
{
weakCell.imageView.image = image;
[weakCell setNeedsLayout];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error: %#", error);
}];
There seem to be some extra space in your url
Your url is https://d2rfichhc2fb9n.cloudfront.net/image/5/Cf7T_BA6- NFGL5ah0w4hdvmk_Vp7InMiOiJzMyIsImIiOiJhZG4tdXNlci1hc3NldHMiLCJrIjoiYXNzZXRzL3VzZXIvZTIvM2MvMjA vZTIzYzIwMDAwMDAwMDAwMC5qcGciLCJvIjoiIn0
Url Without Space
Because of the extra space the image url is invalid and its not getting fetched.
EDIT
NSString *strCorrectUrl = [user.avatar.url stringByReplacingOccurrencesOfString:#" "
withString:#""];

Resources