I have a toy app which submits an https JSON/POST using basic auth security. I've been told I should consider using AFNetworking. I've been able to install AFNetwork-2 into my XCode project (ios7 target, XCode5) just fine. But none of the examples out there seem to be relevant to current versions of AFNetworking-2, but rather previous versions. The AFNetworking docs are pretty sparse, so I'm struggling how to put the pieces together. The non-AFNetworking code looks something like:
NSURL *url = [NSURL URLWithString:@"https://xxx.yyy.zzz.aaa:bbbbb/twig_monikers"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval: 10.0]; NSData *requestData = [NSJSONSerialization dataWithJSONObject: [self jsonDict] options: 0 error: nil]; [request setHTTPMethod: @"POST"]; [request setValue: @"application/json" forHTTPHeaderField: @"Accept"]; [request setValue: @"application/json" forHTTPHeaderField: @"Content-Type"]; [request setValue:[NSString stringWithFormat: @"%d", [requestData length]] forHTTPHeaderField: @"Content-Length"]; NSData *plainPassText = [@"app_pseudouser:sample_password" dataUsingEncoding:NSUTF8StringEncoding]; NSString *base64PassText = [plainPassText base64EncodedStringWithOptions: NSDataBase64Encoding76CharacterLineLength]; [request setValue:[NSString stringWithFormat: @"Basic %@", base64PassText] forHTTPHeaderField: @"Authorization"]; FailedCertificateDelegate *fcd=[[FailedCertificateDelegate alloc] init]; NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO]; [c setDelegateQueue:[[NSOperationQueue alloc] init]]; [c start]; NSData *data=[fcd getData]; if (data) NSLog(@"Submit response data: %@", [NSString stringWithUTF8String:[data bytes]]);
I'm not looking for someone to write my code for me. I just can't seem to figure out how to map the AFNetworking-2 parts over to that. Any links, or examples, or explanations much welcome.
UPDATE 1
The above is a non AF version that is known to work. Moving trying to get it all in one go, I just tried:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"app_pseudouser" password:@"sample_password"]; AFHTTPRequestOperation *operation = [manager PUT: @"https://172.16.214.214:44321/twig_monikers" parameters: [self jsonDict] success:^(AFHTTPRequestOperation *operation, id responseObject){ NSLog(@"Submit response data: %@", responseObject);} failure:^(AFHTTPRequestOperation *operation, NSError *error){ NSLog(@"Error: %@", error);} ];
Which produces the following error:
2013-10-09 11:41:38.558 TwigTag[1403:60b] Error: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x1662c1e0 {NSErrorFailingURLKey=https://172.16.214.214:44321/twig_monikers, NSErrorFailingURLStringKey=https://172.16.214.214:44321/twig_monikers}
Watching on the server side, nothing ever makes it through. I don't know if it is because the https, or what, but I can flip the app back to the original code, and it gets through just fine.
UPDATE: The JSON portion of the following was found to work for PUT/POST, but NOT for GET/HEAD/DELETE
After some wrangling, and help outside SO, I got something working, which I wanted to leave as a memento. In the end, I was really very impressed with AFNetworking-2. It was so simple, I kept trying to make it harder than it should have been. Given a jsonDict
method that returns the json packet to send, I created the following:
- (void) submitAuthenticatedRest_PUT { // it all starts with a manager AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; // in my case, I'm in prototype mode, I own the network being used currently, // so I can use a self generated cert key, and the following line allows me to use that manager.securityPolicy.allowInvalidCertificates = YES; // Make sure we a JSON serialization policy, not sure what the default is manager.requestSerializer = [AFJSONRequestSerializer serializer]; // No matter the serializer, they all inherit a battery of header setting APIs // Here we do Basic Auth, never do this outside of HTTPS [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"basic_auth_username" password:@"basic_auth_password"]; // Now we can just PUT it to our target URL (note the https). // This will return immediately, when the transaction has finished, // one of either the success or failure blocks will fire [manager PUT: @"https://101.202.303.404:5555/rest/path" parameters: [self jsonDict] success:^(AFHTTPRequestOperation *operation, id responseObject){ NSLog(@"Submit response data: %@", responseObject);} // success callback block failure:^(AFHTTPRequestOperation *operation, NSError *error){ NSLog(@"Error: %@", error);} // failure callback block ]; }
3 setup statements, followed by 2 message sends, it really is that easy.
EDIT/ADDED: Here's an example @jsonDict implementation:
- (NSMutableDictionary*) jsonDict { NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; result[@"serial_id"] = self.serialID; result[@"latitude"] = [NSNumber numberWithDouble: self.location.latitude]; result[@"longitude"] = [NSNumber numberWithDouble: self.location.longitude]; result[@"name"] = self.name; if ([self hasPhoto]) { result[@"photo-jpeg"] = [UIImageJPEGRepresentation(self.photo, 0.5) base64EncodedStringWithOptions: NSDataBase64Encoding76CharacterLineLength]; } return result;
}
It should just return a dictionary with string keys, and simple objects as values (NSNumber, NSString, NSArray (I think), etc). The JSON encoder does the rest for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With