NSURLSession“完成处理程序”内的导航不起作用

Posted

技术标签:

【中文标题】NSURLSession“完成处理程序”内的导航不起作用【英文标题】:Navigation inside NSURLSession "completion handler" Not Work 【发布时间】:2016-08-21 19:52:37 【问题描述】:

我有一个点击手势来提交数据:

- (void)tapSubmitDataRecognizer:(UISwipeGestureRecognizer *)sender 

if (_userNameOrEmailTextField.text != NULL) 

    // NSURLSession
    NSString *dataURL = [NSString stringWithFormat: @"http://localhost:8080/api/users/%@", _userNameOrEmailTextField.text];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:dataURL]];
    [request setHTTPMethod:@"GET"];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 

        if (data != nil) 
            // Convert the returned data into a dictionary.
            NSError *error;
            NSMutableDictionary *returnedDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];

            if (error != nil) 
                NSLog(@"%@", [error localizedDescription]);
             else 
                // If no error occurs, check the HTTP status code.
                NSInteger HTTPStatusCode = [(NSHTTPURLResponse *)response statusCode];
                // If it's other than 200, then show it on the console.
                if (HTTPStatusCode != 200) 
                    NSLog(@"HTTP status code = %ld", (long)HTTPStatusCode);
                

                passwordStoredInDatabase = [returnedDict valueForKey:@"password"];

                if ([passwordStoredInDatabase isEqualToString:[self createSHA512:self.passwordTextField.text]]) 

                    NSLog(@"Passwords Match!");

                    UIViewController *demoIntro = [[DemoIntroViewController alloc] init];
                    demoIntro = [self.storyboard instantiateViewControllerWithIdentifier:@"DemoIntroViewController"];
                    [self.navigationController showViewController:demoIntro sender:self];

                 else 
                    NSLog(@"Passwords Not Match!");
                
            
        
    ] resume];

    /**UIViewController *demoIntro = [[DemoIntroViewController alloc] init];
    demoIntro = [self.storyboard instantiateViewControllerWithIdentifier:@"DemoIntroViewController"];
    [self.navigationController showViewController:demoIntro sender:self];*/


如果将导航部分放在完成处理程序中,则除导航部分外,一切正常。

请注意:

1) 密码匹配。

2) 导航部分在完成处理程序之外运行良好。

我需要将导航部分放在里面,因为我需要访问 NSString“passwordStoredInDatabase”。

但是,如果从完成处理程序外部询问,“passwordStoredInDatabase”为空。

如果您能帮我解决其中一个问题:

1) 如何使导航部分在完成处理程序中工作?

2) 如何从外部访问在完成处理程序内部生成的 NSString "passwordStoredInDatabase"?它目前在外面为空,但在里面不为空。变量在最开始的“实现”块中声明如下。

@implementation LoginViewController 
    UITextField *activeTextField;
    NSString *passwordStoredInDatabase;

打印一些调试消息后,可访问性的问题似乎是执行顺序。如何确保 NSURLSession 部分之外的代码在 NSURLSession 部分完成后执行?我试过了

[[NSOperationQueue mainQueue] addOperationWithBlock:^
            completionHandler(data);
        ];

包装 NSURLSession 部分。但是还是不行。

【问题讨论】:

始终在主队列上执行 UI 更新。 @rmaddy 你是对的。现在可以使用了! 【参考方案1】:

即使 UI 更新的问题得到解决,我也不赞成您的代码设计 - 这可能会导致更大的问题。尝试利用面向对象编程 (OOP) 技术。

1) 抽象。保持您的网络层和视图彼此不可知。我建议研究 MVVM 设计模式。避免在一个视图控制器中做所有事情。但是这里有一个例子,如果你想进行网络调用,并在收到响应后导航。

2) 可能有多种方法,例如 NSNotifications、委托模式等。这是一个非常基本的完成块,可以帮助您进行优化设计 -

-(void)initializeLoginFlow:(void (^)(BOOL loginStatus, NSError *error))completionHandler 

    __block NSError *error;
    __block BOOL success;

    // Make a network request using NSURLSession
    // Parse the response and update success object.
    // Make sure to add weakSelf and use strongSelf inside the block.

    if (completionHandler) 
        completionHandler(success, error);
    


- (void)tapSubmitDataRecognizer:(UISwipeGestureRecognizer *)sender 

    [self initializeLoginFlow:^(BOOL loginState, NSError *error) 
        if (loginState) 
            dispatch_async(dispatch_get_main_queue(), ^
                // Navigation. Passwords matched.
            );
        
    ];

【讨论】:

以上是关于NSURLSession“完成处理程序”内的导航不起作用的主要内容,如果未能解决你的问题,请参考以下文章

从自定义类管理 NSURLSession 的完成处理程序

NSURLSession 未下载完整数据,但成功完成

闭包内的 Swift NSURLSession 访问委托

未调用 NSURLSessionDataTask 完成处理程序块

模型、块和完成处理程序 Oh MY

转到不在底部导航视图内的片段并返回后,底部导航视图不起作用