阻止未在iOS中完成

时间:2014-06-17 06:34:58

标签: ios objective-c nsurl

我对iOS开发相对较新,但我正在开发应用程序以更好地了解开发。我正在使用Web服务,并希望检查用户输入的凭据。为此,我使用他们的凭据进行简单的获取请求,然后检查200的http状态。以下是我的代码:

-(BOOL)checkCredentials:(NSString *)username withPassword:(NSString *)password{

    NSString *requestString = @"SOME URL";
    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    NSData *userPasswordData = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
    NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
    NSString *authString = [NSString stringWithFormat:@"Basic %@", base64EncodedCredential];

    NSURLSessionConfiguration *sessionConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.HTTPAdditionalHeaders=@{@"Authorization":authString};

    self.session=[NSURLSession sessionWithConfiguration:sessionConfig];
    __block BOOL success = NO;

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

        if(!error){
            NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
            if (httpResp.statusCode == 200) {
                success = YES;
            }
        }
        NSMutableDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", jsonObject);
        dispatch_semaphore_signal(sema);
    }];

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

    [dataTask resume];
    return success;
}

我打算使用信号量等待块完成,这样我就可以检查状态码然后返回。但首先看起来我的代码只是悬而未决,我认为因为我没有发布,但ARC不允许这样做。我不确定为什么要挂。有没有更好的方法来等待块完成(没有信号量)所以我可以返回我的凭据是否有效?

还有更好的方法来传递用户名和密码,以免某人欺骗用户名和密码吗?

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:4)

想想简单!

制作自己的completionHandler,以便您不再处理return,来电者将负责结果验证。

您需要记住的一件事是,如果您想要修改与UI(用户界面)相关的任何内容,您需要将完成块调度到主队列,否则您将遇到意外行为,请参阅更多细节here

将您的return类型更改为void并添加completion block

-(void)checkCredentials:(NSString *)username withPassword:(NSString *)password completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))myCompletion
{

    NSString *requestString = @"http://google.com";
    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        // Here you return exactly what the NSURLSessionDataTask downloaded
        // and pass it to the caller as an another completion block
        myCompletion(data, response, error);
    }];


    [dataTask resume];
}

来电者的代码,我认为self是来电者:

[self checkCredentials:@"" withPassword:@"" completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if(!error){
            // Result verification's here 
            NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
            if (httpResp.statusCode == 200) {
                NSLog(@"SUCESS");
            }
        }
    }];

答案 1 :(得分:3)

您的代码停止等待信号量,[dataTask resume]永远不会被执行。

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); <=== waits here

[dataTask resume];                                    <=== never reached

我建议不要在这里使用信号量。而是在你的街区工作。

至于用户名/密码。如果您担心欺骗,那么HTTP上的SSL层就是答案。

答案 2 :(得分:2)

这是一个非常危险的模式,因为此调用将在网络请求完成之前阻塞。如果这是在主线程上,你的应用程序将停止响应,看门狗可能会杀了你。

除了该警告之外,该块未完成的原因是因为网络任务从未启动过。在调用resume之前,您会在信号量上陷阱,因此您的任务永远不会运行。我也会亲自使用dispatch_group来做等待。

为了使它更好,你需要异步重写它。基本上你的应用程序继续运行,可能会禁用输入,直到调用完成,然后运行一个块重新启用它们,或显示错误:

// Assume your login button and whatever are exposed as properties here
self.loginButton.enabled = NO;
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  if(!error){
    NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
    if (httpResp.statusCode == 200) {
      success = YES;
    }
  }
  NSMutableDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  NSLog(@"%@", jsonObject);
  // Need to be back on the main queue, the call is complete
  self.loginButton.enabled = YES;
}];
[dataTask resume];

或者,只是为了保持它的方式,但解决眼前的问题,重新命令陷阱,以便在任务恢复后发生:

[dataTask resume];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // might want to time out here instead of waiting forever
return success;