I am trying to isolate logic responsible for authentication and retriving the TOKEN inside the function. I have the problem with returning the string with token from BLOCK of NSURLConnetcion.
It causues semantic error
: Incompatible block pointer types sending
'NSString *(^)(NSURLResponse *__strong, NSData *__strong, NSError *__strong)'
to parameter of type
'void (^)(NSURLResponse *__strong, NSData *__strong, NSError *__strong)'
I am completly newbie to Objective-C, so please be forgiving. Below is my function.
- (NSString*)getToken: (NSString *)username andPassword: (NSString *) password {
NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:@"http://127.0.0.1:8000/auth_ex"]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20];
__block NSString * tokens;
[request1 setHTTPMethod:@"POST"];
NSString * body1 = [NSString stringWithFormat:@"email=%@&password=%@",username,password];
[request1 setHTTPBody: [body1 dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue * queue1 = [[NSOperationQueue alloc]init];
[NSURLConnection
sendAsynchronousRequest:request1 queue:queue1 completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if ([data length] >0 && connectionError == nil){
NSDictionary* token = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
tokens = [token objectForKeyedSubscript:@"token"];
return tokens;
}
else{
return @"NOT AUTHORIZEd";
}
}];
}
There are a couple of issues.
Naming Conventions
Your method getToken:andPassword:
should be asynchronous.
Improper use of NSOperationQueue
(you don't need that)
No Content-Type header specified
Omitting parameter encoding in the Query component of the URI (x-www-form-urlencoded
)
Some lack of experience which NSURLConnection
:
Don't use class convenience methods unless you know exactly that your request works with the implemented default behavior (for requests with authentication this is almost always never the case). Please read the official docs
- sendAsynchronousRequest:queue:completionHandler:
- URL Loading System Programming Guide
So, for a solution, I would suggest the delegate approach of either NSURLConnection
or NSURLSession
. See examples and code snippets in the official docs already mentioned above.
You will have to handle an authentication challenge, where you provide the credentials. This also frees you from the error prone and inconvenient need to percent encode the parameters if you would put them into the URL or the body.
You should also use https
.
The variable tokens
is declared outside of the block but accessible from inside the block. Therefore the if
statement doesn't need to return tokens
and the else statement should just be tokens = @"NOT AUTHORIZED";
Note that your block is being called from some framework code, and that code doesn't expect anything to be returned, hence the completionHandler is declared as void
, and you aren't allowed to return values from a void
function.
I should add that the sendAsynchronousRequest
method will return almost immediately, but the completion handler won't be called until sometime later, after the server responds to the request. So typically the completion handler is used to notify the main thread that the operation has completed. One way to notify the main thread is with code like this
[self performSelectorOnMainThread:@selector(someMethod:) withObject:tokens waitUntilDone:NO];
where the someMethod
method is declared as
- (void)someMethod:(NSString *tokens)
{
}
That way, you can do something with the results after the network request has finished.