return string inside block of NSURLConnection - In

2019-07-18 02:35发布

问题:

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";
     }
 }];


}

回答1:

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.



回答2:

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.