setDownloadProgressBlock in AFHTTPClient subclass - objective-c

I created subclass of AFHTTPClient.
It works, but progress block return only final value (1.0). What should I change to get all the calculated values from setDownloadProgressBlock?
- (void)exploreVenuesCenter:(CLLocationCoordinate2D)coordinate inRadius:(int)radiusMeters success:(void (^)(NSArray *venues))success failure:(void (^)(NSError *error))failure progress:(void (^)(float progress))progress{
NSDictionary *parameters = #{#"limit": #"10",
#"client_id":kFoursquareClientID,
#"client_secret":kFoursquareClientSecret,
#"radius":#(radiusMeters).stringValue,
#"ll":[NSString stringWithFormat:#"%g,%g",coordinate.latitude, coordinate.longitude],
#"v":kFoursquareVersion};
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:#"venues/explore" parameters:parameters];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *items = responseObject[#"response"][#"groups"][0][#"items"];
if (success)
{
success(items);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) {
failure(error);
NSLog(error.localizedDescription);
} }];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//
float progressNo = ((float)totalBytesRead) / totalBytesExpectedToRead;
if (progress) {
progress(progressNo);
}
}];
[self enqueueHTTPRequestOperation:operation];
}

Related

AFNetworking 1.x to 3.x migration for NSURLSessionTask?

I have a old project which is not working in iOS 9. I've read official documentation on AFNetworking and completed most of the migration.
NetworkManager:
_requestManager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:baseURL ]];
//here we can set the request header as the access token once we have logged in.
AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
[_requestManager setRequestSerializer:requestSerializer];
[_requestManager setResponseSerializer:responseSerializer];
Earlier Version:
// 2. Create an `NSMutableURLRequest`.
NSMutableURLRequest *request =
[[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:fullPath
parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
}];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
AFHTTPRequestOperation *operation =
[[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
success: ^(AFHTTPRequestOperation *operation, id responseObject) {
result(YES, #"");
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.responseData) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];
result(NO, [responseDict valueForKey:#"Message"]);
[self deleteTmpFilesFromParts:formParts];
} else {
result(NO, [NSString stringWithFormat:#"Failed to upload media to %#!", gallery.gallery_name]);
[self deleteTmpFilesFromParts:formParts];
}
result(NO, errorMessage);
}];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
DLog(#"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
}];
// 5. Begin!
[operation start];
Converted Response: ( updated with comments what gives errors )
//No visible #interface for 'AFHTTPRequestSerializer<AFURLRequestSerialization>' declares the selector 'multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:'
NSMutableURLRequest *request =
[[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:fullPath parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
}];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
//No visible #interface for 'AFHTTPSessionManager' declares the selector 'HTTPRequestOperationWithRequest:success:failure:'
NSURLSessionTask *operation =
[[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
success: ^(NSURLSessionTask *operation, id responseObject) {
result(YES, #"");
} failure: ^(NSURLSessionTask *operation, NSError *error) {
//Error for operation doesn't have responseData
if (operation.responseData) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];
result(NO, [responseDict valueForKey:#"Message"]);
[self deleteTmpFilesFromParts:formParts];
} else {
result(NO, [NSString stringWithFormat:#"Failed to upload media to %#!", gallery.gallery_name]);
[self deleteTmpFilesFromParts:formParts];
}
// get the response
result(NO, errorMessage);
}];
// 4. Set the progress block of the operation.
//No visible #interface for 'NSURLSessionTask' declares the selector 'setUploadProgressBlock:'
[operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
DLog(#"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
}];
// 5. Begin!
//No visible #interface for 'NSURLSessionTask' declares the selector 'start'
[operation start];
The equivalent code for AFHTTPSessionManager is simply:
NSURLSessionTask *task = [[[NetworkManager sharedInstance] requestManager] POST:fullPath parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
NSLog(#"%.3f", uploadProgress.fractionCompleted);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// success
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// failure
// if you need to process the `NSData` associated with this error (if any), you'd do:
NSData *data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
if (data) { ... }
}];
This features two major changes from your v1.x code: First, with 2.x they introduced GET/POST/etc. methods that saved you from manually starting the operation (or adding it to your own queue). Second, with 3.x, they retired NSOperation framework of AFHTTPRequestOperationManager, and now use AFHTTPSessionManager class, where GET/POST/etc. don't return an NSOperation subclass, but rather a NSURLSessionTask reference.

return data from AFHTTPRequestOperation?

I'm moving my app code to an MVC model and so I created a method to retrieve some data from an API.
+ (NSMutableArray *)loadFromFeed {
NSString *feed = #"https://api.test.com";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedUrl]];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [JSONResponseSerializerWithData serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
CLS_LOG(#"Error");
}];
}
Now, ideally, I'd like to return jsonArray as part of this method. However, since AFHTTPRequestOperation is asynchronous, I don't know how to solve this and still be able to call [Data loadFromFeed]; anywhere in the app. How can I do this?
You could pass two block named success and failure to loadFromFeed ,
and then call the two block from your setCompletionBlockWithSuccess success and failure block, passing jsonArray to the success block:
typedef void (^Success)(id data);
typedef void (^Failure)(NSError *error);
- (void)loadFromFeed:(Success)success failure:(Failure)failure;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
success?success(jsonArray):nil;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure?failure(error):nil;
}];
then use in this way:
[Data loadFromFeed:^(id data) {
NSLog(#"%#",data)
} failure:^(NSError *error) {
NSLog(#"%#",error)
}];];

asynchronous function doesn't return data

I wrote a function to fetch an NSDictionary from a URL.
[Data loadFromAPI:#"http://example.com/api" withSuccess:^(id data) {
NSMutableDictionary *result = (NSDictionary *)data;
CLS_LOG(#"result: %#", result);
} failure:^(NSError *error) {
CLS_LOG(#"Error: %#", error);
}];
The function it calls is the one below:
typedef void (^Success)(id data);
typedef void (^Failure)(NSError *error);
+ (void)loadFromAPI:(NSString *)apiURL withSuccess:(Success)success failure:(Failure)failure {
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:apiURL]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [JSONResponseSerializerWithData serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)responseObject ;
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:
[self now], #"time",
jsonArray, #"response",
nil];
CLS_LOG(#"Result is: %#", result);
success(result);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure?failure(error):nil;
}];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue addOperations:#[operation] waitUntilFinished:NO];
}
Inside the function CLS_LOG(#"Result is: %#", result); returns the data returned. However, where I call the function CLS_LOG(#"result: %#", result); returns null. What am I doing wrong?
As it turns out [self now] returned null, so the NSDictionary wasn't being set properly.
The problem is
NSMutableDictionary *result = (NSDictionary *)data;
you cant directly do that, i wonder why you dont have a warning for that..
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithDictionary:(NSDictionary *)data];
will probably solve the problem...

Cancel AFHttpRequestOperation

I'm downloading the image using AFHttpRequestOperation, i want to cancel this operation on a button click.How do i do this
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:strImagePath]];
self.managerDownloadActualImage = [AFHTTPRequestOperationManager manager];
self.managerDownloadActualImage.responseSerializer = [AFHTTPResponseSerializer serializer];
self.operationImageDownload = [self.managerDownloadActualImage HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Download succeeded.");
chatData.isDownloaded = [NSNumber numberWithBool:YES];
chatData.isThumbDownloaded = [NSNumber numberWithBool:YES];
NSData *responseData = (NSData *)responseObject;
chatData.actual_path = [NSString stringWithFormat:#"%#",[self saveImageInDocumemntDirectoryWithImageData:responseData]];
[self saveData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Download failed with error: %#", error);
}];
[self.operationImageDownload setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"Bytes read: %lu", (unsigned long)bytesRead);
NSLog(#"Total bytes read %lld", totalBytesRead);
NSLog(#"Total progress: %Lf", (long double)totalBytesRead / totalBytesExpectedToRead);
int currentPercentage = ((long double)totalBytesRead / totalBytesExpectedToRead) * 100;
if (currentPercentage <= 100) {
self.customProgressView.percent = currentPercentage;
[self.customProgressView setNeedsDisplay];
}
else {
[self.customProgressView removeFromSuperview];
}
}];
NSLog(#"Starting download.");
[self.operationImageDownload start];
i had used
[self.managerDownloadActualImage.operationQueue cancelAllOperations];
but this does not stop the download process.

Creating dependencies between operations when using AFHTTPRequestOperation

I'm working with AFNetworking (2.4.1) in a mac application. I'm hoping to add my own block operation that is for after completion of all of the other operations (which are AFHTTPRequestOperation). I have tried adding dependencies between the completionOperation and the others, but the completionOperation block still executes before the others have completed with success or failure.
A cut down version of the code that illustrates the basics is below. Is anyone able to suggest how to make this work? Thanks.
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"All operations complete");
}];
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:[[NSURL URLWithString:#"https://api.parse.com/1/classes/SomeClass"] absoluteString] parameters:nil error:nil];
AFHTTPRequestOperation *operation1 = [manager HTTPRequestOperationWithRequest:request1 success:
^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"operation 1 success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"operation 1 failure");
}];
NSMutableURLRequest *request2 = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:[[NSURL URLWithString:#"https://api.parse.com/1/classes/OtherClass"] absoluteString] parameters:nil error:nil];
AFHTTPRequestOperation *operation2 = [manager HTTPRequestOperationWithRequest:request2 success:
^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"operation 2 success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"operation 2 failure");
}];
[completionOperation addDependency:operation1];
[completionOperation addDependency:operation2];
[manager.operationQueue addOperation:operation1];
[manager.operationQueue addOperation:operation2];
[manager.operationQueue addOperation:completionOperation];
- (void) test3:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// block 1
NSString *string = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *urll = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:urll];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"OPERATION 1 %#",responseObject );
test_Sync = #"done";
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
test_Sync = #"faile"; }];
//block 2
NSString *string2 = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *urll2 = [NSURL URLWithString:string2];
NSURLRequest *request2 = [NSURLRequest requestWithURL:urll2];
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request2];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation2, id responseObject) {
// Print the response body in text
NSLog(#"Response: OPERATION 2 %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation2, NSError *error) {
NSLog(#"Error: %#", error);
}];
// Add the operation to a queue
// It will start once added
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
// Make operation2 depend on operation1
[operation addDependency:operation2];
[operationQueue addOperations:#[operation, operation2] waitUntilFinished:YES];
}