Handle single download via afnetworking is good my question is that how handle multiple click on different button then it call this method then process break previous.
it is bcoz suppose several button hit at time then it confuse to download. how handle multiple download in selector method,if in array of batch download then it's easy but through which how .
-(void)downloadimagefromserver:(UIButton *)sender
{
int index =(int) sender.tag;
historyclass *class1 = [messages objectAtIndex:index];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:arrayOfStringsfinal[1]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
Related
I am new to AFNetworking and I am having a nightmare of a time with it.
So far I have created this method:
-(void)UserLogin:(NSString *)user andPassWordExists:(NSString *)password completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{
NSURL *url = [NSURL URLWithString:kIP];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[operation setCredential:[NSURLCredential credentialWithUser:[#"domain" stringByAppendingString:user]
password:password persistence:NSURLCredentialPersistenceForSession]];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[[NSOperationQueue mainQueue] addOperation:operation];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionHandler) {
completionHandler(nil, error);
}
}];
[operation start];
}
I am just super confused on what the next step would be. I have this other method inside another file and I would like to call the UserLogin method and pass in a username and password, would I want to do this like this:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName User:self.idTextField.text andPassWordExists:self.passwordTextField.text:^(id responseObject, NSError *error) {
if (responseObject) {
//We have a user.
}
}];
}
The idea of your second snippit is correct but it's unclear what the "userName" object is. That should be an instance of the class where the first snippit's method can be located, and the name of the method you created was "UserLogin" (you put "User").
How can I run multiple requests inside the success block of 1 request and wait for it to finish?
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
[self getDetails:json];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Where in getDetails:(id)json is the method to load the group of requests whose parameters are based on the result of the main request.
For example:
I would like to request from the API a list of students, then on the success block. For each student, I would like to get the related data from another table (another request) and put them on my NSObject.
EDIT Here is my getDetails method
- (AFHTTPRequestOperation *)getDetails:(NSDictionary *)json
{
NSLog(#"Start Op %#",[json objectForKey:#"related_salon"]);
NSString *url = [NSString stringWithFormat:#"%#read/salons/%#",SERVER_API_URL,[json objectForKey:#"related_salon"]];
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success %#",[json objectForKey:#"name"]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failed Op %#",error.localizedDescription);
}];
//AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op start];
return op;
}
The AFNetworking GET method returns a ATHTTPRequestOperation (an NSOperation subclass). You could have your getDetails method return that object. You can then create a new operation dependent upon those operations, which you'd run at the end:
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
// add here whatever you want to perform when all the getDetails calls are done,
// e.g. maybe you want to dismiss your HUD when all the requests are done.
[SVProgressHUD dismiss];
}];
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
NSOperation *operation = [self getDetails:json];
[completionOperation addDependency:operation];
}
[[NSOperationQueue mainQueue] addOperation:completionOperation];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Again, this is presuming that getDetails is doing its own GET call, and that you change getDetails to (a) capture the NSOperation returned by GET and (b) return it.
Im using AFNetworking 2, with AFHTTPRequestOperation I can use for my Get
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"GET"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.securityPolicy = securityPolicy;
[operation setWillSendRequestForAuthenticationChallengeBlock:
^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
//the certificate
}
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
DLog(#"operation :: %#", responseObject);
NSString *result = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
DLog(#"operation :: %#", result);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(#"operation error :: %#", error);
}];
[operation start];
But now i need to use POST, with parameters,
I have problems finding how to set parameters on
AFHTTPRequestOperation
or finding how to set challenge block for
AFHTTPRequestOperationManager
how to have a POST with parameters and challenge block?
cheers
I am working now on the POST request. So far I've came up with the following code while trying to send an NSDictionary with POST method:
NSDictionary*packet = [NSDictionary dictionaryWithObjectsAndKeys: ......
[manager POST:path
parameters:packet
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
if ([responseObject isKindOfClass:[NSDictionary class]])
[self parseReceivedDataPacket:responseObject];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Actually it works for me, apart from getting an "unacceptable content-type: text/html" when sending this data. But it gets received.
Hope this was useful.
I need to check the size of file from a URL. I get the file size perfectly when downloading file with AFNetworking.
AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Success Callback
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Failure Callback
}];
and get file size in another block
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
}];
But i need to check file size before initiating download request, so that i can prompt to user. I have also tried another method
NSURL *url = [NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(#"original = %d", [data length]);
But it blocks the UI, coz it download all data to calculate its size.
Is there any way to check file size before downloading? Any help is appreciated.
If the server supports it you can make a request to just get the headers (HEAD, as opposed to GET) without the actual data payload and this should include the Content-Length.
If you can't do that then you need to start the download and use expectedContentLength of the NSURLResponse.
Basically, create an instance of NSMutableURLRequest and call setHTTPMethod: with the method parameter set to #"HEAD" (to replace the default which is GET). Then send that to the server as you currently request for the full set of data (same URL).
here is the code:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidateURL];
[request setHTTPMethod:#"HEAD"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Content-lent: %lld", [operation.response expectedContentLength]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I am using AFNetworking and I've read that synchronous responses are discouraged. yet I need to check whether a user already exist in the online database before the person can go to the next stage of the app. Yes, a typical registration process.
My code as it stands it returns NO because is asynchronous. I need to find a way to check for the success call and return YES or NO depending on this callback.
Could anyone point me in the right direction of how to write an app that waits for the success call so that I know that the user has not been set?
-(BOOL)doesTheUserExistAlreadyOnServer:(NSString *)parsedEmail
{
BOOL *methodResponse = NO;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.myurl.co.uk/"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"http://www.myurl.co.uk/igym.php"
parameters:#{#"myvar2":#"piggy"}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
// NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
if ([[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] isEqualToString:#"piggy"]) {
__block methodResponse = YES;
NSLog(#"%#",[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
return (BOOL)methodResponse;
}
EDIT:
I solved the problem using the following logic.
The user clicks on the registration button. The main method does all the preliminary non-web checks, then calls the [self doesTheUserExistAlreadyOnServer:_email.text];
that method code is now
-(void)doesTheUserExistAlreadyOnServer:(NSString *)parsedEmail
{
if(![_spinner isAnimating])
{
[_spinner startAnimating];
}
__block RegistrationViewController* me = self;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.myurl.co.uk/"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"http://www.myurl.co.uk/igym.php"
parameters:#{#"myvar2":#"piggy"}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
if ([[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] isEqualToString:#"piggy"]) {
NSLog(#"%#",[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
[me registrationPartTwo:YES];
} else
{
[me registrationPartTwo:NO];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
Then once that block/callback is successful it calls
-(void)registrationPartTwo:(BOOL)doesItExistOnServer
{
[_spinner stopAnimating];
NSString *emailAlreadyInUseMessage = [NSString stringWithFormat:#"This email is already in use"];
if (doesItExistOnServer)
{
self.screenMsg.text = emailAlreadyInUseMessage;
//here more code to send the user the the next step
}
}
basically i solved this using a 2method registration process dependant upon callback, dont know if thats the best or most efficient way. but thats the way i could solve it on my own.
Use a delegate callback to notify when the operation completes. If needed, before starting the operation, put up an UIActivityIndicatorView (the spinner) to prevent the user from interacting with the app.