I'm using AFImageRequestOperation to download hundreds of jpg from my server.
NSURLRequest *request = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:20];
AFImageRequestOperation *operation;
operation = [AFImageRequestOperation imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}
];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:[[paths objectAtIndex:0] stringByAppendingPathComponent:picture] append:NO];
[downloadQueue addOperation:operation];
If I now want to cancel the download in progress I execute [downloadQueue cancelAllOperations].
With the previous version of AFNetworking that I used (earlier this year) this worked perfectly but with the recent one I get this:
ERROR [http://myImageURL] -- The operation couldn’t be completed. (NSURLErrorDomain error -999.)
for all pending operations.
Do I have to to do some additional stuff now?
In NSURLErrorDomain, that error code is defined as follows:
kCFURLErrorCancelled = -999
...which makes sense, since the operation was indeed cancelled. This is not a bug, but an expected behavior. The change may be either a documented change to AFNetworking, or an undocumented one in NSURLConnection between iOS versions.
Related
I'm using AFImageRequestOperation to download hundreds of jpg from my server.
NSURLRequest *request = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:20];
AFImageRequestOperation *operation;
operation = [AFImageRequestOperation imageRequestOperationWithRequest:request
imageProcessingBlock:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}
];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:[[paths objectAtIndex:0] stringByAppendingPathComponent:picture] append:NO];
[downloadQueue addOperation:operation];
If I delete them all (removing all images in Documents Folder) and start download again, the first X (depends on how far I got during last download process) operations are processed immediately. It seems like the images downloaded from the previous process are stored (cached) somewhere. I also checked the Documents Folder for the simulator and the images are downloaded correctly. So how can I make sure the download process really starts from the beginning?
When you're creating the NSURLRequest, use this instead:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:theURL];
request.cachePolicy = NSURLRequestReloadRevalidatingCacheData;
This policy is described in the docs the following way: Specifies that the existing cache data may be used provided the origin source confirms its validity, otherwise the URL is loaded from the origin source.
You can check the cache policies of NSURLRequest here.
I have a problem with completion block in AFNetworking, my app needs to get json data about car and use id from this json file to request another api to retrieve images before displaying all cars in uitableview. But the uitableview reload is always called before retrieving information so it displays empty table.
I have a Model.m
typedef void (^CompletionBlock)(NSArray *results);
-(void)getPhotosWithCompletionBlock: (CompletionBlock)completionBlock failureBlock: (FailureBlock)failureBlock{
NSURLRequest *request = [NSURLRequest alloc] initWithURL:[NSURL alloc] initWithString:
[NSString stringWithFormat:#"api.getPhoto"]]];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
completionBlock(JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
failureBlock(JSON);
}];
[operation start];
}
ModelViewController.m
- (void)getAllModels{
NSURLRequest *request = ...;
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
for(NSDictionary *model in JSON){
Model *model = [Model alloc] initWithId:...;
[model getPhotosWithCompletionBlock: ^(NSArray *results){
model.photos = results;
}failureBlock:^(NSError *error) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
}
[_tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
But [_tableView reload] is always called before completionBlock of getPhotos method finish so there's an empty tableView, so how to make completion block finish before calling reload tableView method? I can put reload method inside completion block but it forces tableView reload many times makes app very unresponsive, I have 1 more method to retrieve model info so I cannot put reload method inside every completion blocks.
P/S: any idea for my situation without using nested afnetworking operations?
This is not an AFNetworking related question, rather a general Objective-C or
asynchronous question.
You may try to reload the table view whenever the images of one model have been loaded:
- (void)getAllModels{
NSURLRequest *request = ...;
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
for(NSDictionary *model in JSON){
Model *model = [Model alloc] initWithId:...;
[model getPhotosWithCompletionBlock: ^(NSArray *results){
dispatch_async(dispatch_get_main_queue(), ^{
model.photos = results;
[self.tableView reloadData];
});
}failureBlock:^(NSError *error) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
You likely need to fix some edge cases when an error occurs.
If there are performance issues, you need to check where they occur. One usual suspect is the creation of UIImages on the main thread. You may schedule them to another embedded async task whose completion block then forces an update of the table view, or perform this in your getPhotosWithCompletionBock method.
You may also consider to be more explicit about which cell you need to update instead just simply sending reloadData: which will also reload images which are already up to date.
I am loading a bunch of images using AFNetworking and I would like to scale and apply rounded corners to these images before AFNetworking caches them.
I started out scaling and applying rounded corners to the images each time they were loaded but the completion block will also be called when the image is loaded from the cache and therefore this uses too many resources when a user scrolls a collection view filled with images.
[self.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:10.0f]
placeholderImage:kVideoCollectionViewCellVideoImagePlaceholder
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
/**
* The image is edited here and this block is called
* when the image is loaded from web and from the cache.
*/
[self.imageView setImage:image];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
DDLogError(#"%#", error);
}];
AFNetworking seems to provide a great cache for my use, especially when I enable disk caching therefore I would like to use it but I can't figure out if there's a way to edit the image before it is cached.
Does anyone know if this is possible and if so, how it can be done?
After posting the question it hit me that I may have too look in another direction that using the UIImageView+AFNetworking category. Using the AFImageRequestOperation directly solved the problem.
__weak NZVideoCollectionViewCell *weakSelf = self;
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:10.0f];
AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request imageProcessingBlock:^UIImage*(UIImage *image) {
/**
* Edit image.
*/
return editedImage;
}
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[weakSelf.imageView setImage:image];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
DDLogError(#"%#", error);
}];
[operation start];
I was wondering how i would get AFNetworking code to visit a link on my web server(PHP Script) and get the response data, and put it into a string?
Could anyone post an example of this?
Thanks alot!
here is the required code to get response from server using AFNETWorking.Just add AFNetworking Library and the Required frameWorks.After that use the below code.
NSURL *url = [[NSURL alloc] initWithString:#"http://itunes.apple.com/search?term=harry&country=us&entity=movie"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"JSON");
self.movies = [JSON objectForKey:#"results"];
[self.tbleView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
self.movies is name of mutable Array you can use any name instead of this.
Also you can check here
https://github.com/AFNetworking/AFNetworking
AFHTTPRequests get passed default NSURLRequest objects. stock ones - no modification for AFNetwork
to build THAT see
How to add GET parameters to an ASIHttpRequest?
i have a little problem with this, I'm loading an Image from a Url like this:
+ (void)getImageFromURL:(NSString *)imageFilename urlMode:(NSString *)mode block:(id (^)(UIImage *responseImage))aImage {
NSURL *url = [NSURL URLWithString:[mainURL stringByAppendingString:mode]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
AFImageRequestOperation *requestOperation = [AFImageRequestOperation imageRequestOperationWithRequest:request
imageProcessingBlock:nil
cacheName:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
{
aImage(image);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
{
// manage errors
}];
[[[NSOperationQueue alloc]init] addOperation:requestOperation];
}
I'm trying to set an iVar UIImage *userAvatar to the response from this request, but the problem is, since its an async request I'm not getting the iVar set before my Code moves on, so my iVar is empty when I'm accessing it and passing it to another method.
That's the nature of asynchronous programming! You are going to have to redesign the dependencies on userAvatar to take into account that it's availability is nondeterministic.
So, rather than having your operation's success block simply set the userAvatar ivar, it takes care of whatever needs to happen once that image is available. For example if you want to set a UIImageView's image, then in your success block:
dispatch_async(dispatch_get_main_queue(), ^{
myImageView.image = image;
});
(Without knowing the details of your goals and details of your implementation, this is just a "for example...")
You forgot to add [requestOperation start]; at the end.