Search code examples
iosuistoryboardseguetouch-id

App stops after calling performSegue inside Touch ID block


Hi I’m experiencing a strange behavior I really don’t understand.

I present a touch ID identification to the user and if he’s authorized I call a [self performSegueWithIdentifier: @"callCustomSegue" sender:self]; inside the block in this way:

[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                  localizedReason:myLocalizedReasonString
                            reply:^(BOOL success, NSError *error) {
                                if (success) {
                                    [self performSegueWithIdentifier: @"callCustomSegue" sender:self];

Then the app stops for several seconds (at least 3-4) then next ViewController is presented.

The perform called by “callCustomSegue” does this:

- (void) perform {

    src = (UIViewController *) self.sourceViewController;
    dst = (UIViewController *) self.destinationViewController;

    [src.view addSubview:dst.view];

}

I don’t understand what’s happening between the identification on touch ID and the performSegueWithIdentifier and why the app stops.

If I bypass the touch ID and just call the performSegueWithIdentifier works immediately as I would expect.

If I put in the touch ID block:

[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                  localizedReason:myLocalizedReasonString
                            reply:^(BOOL success, NSError *error) {
                                if (success) {
                    authenticated = YES;
                        [self showMessage:@"Authentication is successful" withTitle:@"Success"];
                }

where showMessage does this:

 UIAlertController * alert=   [UIAlertController
                                  alertControllerWithTitle:title
                                  message:message
                                  preferredStyle:UIAlertControllerStyleAlert];


    UIAlertAction* cancel = [UIAlertAction
                             actionWithTitle:@"OK"
                             style:UIAlertActionStyleDefault
                             handler:^(UIAlertAction * action)
                             {
                                 [alert dismissViewControllerAnimated:YES completion:nil];

                                 if (authenticated) {
                                     [self performSegueWithIdentifier: @"callCustomSegue" sender:self];
                                 }

                                 if (!authenticated) {
                                     [self touchID];
                                 }

                             }];

after tapping OK the next ViewController is called immediately.

So the question is: why I can’t call performSegue within the touch ID block and get an immediate response?

Any idea where I’m wrong?

Thank you so much.


Solution

  • You should perform all UI related activities on the main queue. The reply block for the touchID process is not guaranteed to be executing on the main queue. In fact you can almost guarantee that it won't be.

    You should have -

      if (success) {
         authenticated = YES;
         dispatch_async(dispatch_get_main_queue(), ^{ 
            [self performSegueWithIdentifier: @"callCustomSegue" sender:self];
         });