0

ich eine Tippgeste Daten einreichen:Navigation innerhalb NSURLSession „Abschluss-Handler“ nicht funktionieren

- (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];*/ 
} 
} 

Alles funktioniert gut, außer dem Navigationsteil, wenn das Teil innerhalb der Abschluss-Handler gesetzt wird.

Bitte beachten Sie:

1) Die Passwörter übereinstimmen.

2) Der Navigationsteil funktioniert außerhalb des Completion-Handlers.

Ich muss den Navigationsteil einfügen, weil ich Zugriff auf den NSString "passwordStoredInDatabase" haben muss.

Wenn Sie jedoch von außerhalb des Beendigungshandlers fragen, ist "passwordStoredInDatabase" null.

Wenn Sie mich entweder eines der Probleme lösen helfen:

1) Wie kann ich den Navigationsteil der Arbeit innerhalb der Fertigstellung Handler machen?

2) Wie kann ich von außen auf den NSString "passwordStoredInDatabase" zugreifen, der im Completion-Handler generiert wird? Es ist derzeit null außerhalb, aber nicht null innen. Die Variable wird im Block "Implementierung" gleich zu Beginn wie folgt deklariert.

@implementation LoginViewController { 
    UITextField *activeTextField; 
    NSString *passwordStoredInDatabase; 
} 

Nach dem Drucken einiger Debug-Nachrichten scheint das Problem mit der Zugänglichkeit die Reihenfolge der Ausführung zu sein. Wie kann ich sicherstellen, dass der Code außerhalb des NSURLSession-Teils ausgeführt wird, nachdem der NSURLSession-Teil abgeschlossen wurde? Ich habe versucht

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

um den NSURLSession Teil zu wickeln. Aber es hat immer noch nicht funktioniert.

+1

immer UI-Updates auf der Hauptwarteschlange ausführen . – rmaddy

+0

@rmaddy Sie haben Recht. Es funktioniert jetzt! –

Antwort

2

Obwohl das Problem mit der UI-Aktualisierung gelöst ist, bin ich nicht für Ihren Code-Design - was größere Probleme verursachen kann. Versuchen Sie, die Techniken der objektorientierten Programmierung (OOP) zu nutzen.

1) Abstraktion. Behalten Sie Ihre Netzwerkschicht und Ansichten unabhängig voneinander. Ich würde vorschlagen, in MVVM Entwurfsmuster zu schauen. Vermeiden Sie, alles in einem View-Controller zu machen. Aber hier ist ein Beispiel, wenn Sie einen Netzwerkanruf tätigen möchten, und navigieren Sie nach Erhalt der Antwort.

2) Es kann mehrere Ansätze sein, wie NSNotifications, Delegierter Muster etc. Dies ist ein sehr einfacher Abschluss Block, die Ihnen mit einem optimalen Design helfen würden -

-(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. 
      }); 
     } 
    }]; 
} 
Verwandte Themen