解决使用Touch ID API在回调时界面“长时间卡住”的问题

  Touch ID是iOS8上新公开的API,关于详细介绍和用法可以看CocoaChina的这两篇文章:,在此篇文章中不再赘述。

  我在app中需要的效果是如果touch id验证通过,则页面push到下一个viewController,否则本视图的数字密码输入框becomeFirstResponder。研究过touch id的人应该知道,这段代码大概会这么实现:

 1   LAContext *context = [[LAContext alloc] init];
 2     NSError *error;
 3     
 4     BOOL canUse = [context canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
 5     if (canUse) {
 6         [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
 7                 localizedReason:@"使用touch ID来打开" 
8
reply:^(BOOL success, NSError *authenticationError) { 9 if (success) { 10 //push视图 11 } else { 12 //弹出输入框 13 } 14 }]; 15 }

  我一开始确实也是这么写的,结果发现,验证完成后,无论是否成功,界面都会卡了5秒以上才会进行下一步。这显然不科学啊,然后仔细看了一下这个方法的说明,在网上搜索一番,最后在stackoverflow的帮助下才弄清。一晚上时间的成果。。。。

  我们先看一下- (void)evaluatePolicy:(LAPolicy)policy localizedReason:(NSString *)localizedReason reply:(void (^)(BOOL success, NSError *error))reply这个方法对最后一个参数reply这个block的描述:

reply

Reply block that is executed when policy evaluation finishes. This block is evaluated on a private queue internal to the framework in an unspecified threading context. You must not call canEvaluatePolicy:error: in this block, because doing so could lead to deadlock.

注意第二句话,大概意思是(英语不是很好,轻喷):这个block会在framework内部的一个私有队列中进行判断,而这个framework更是在一个不确定的线程中。。。说简单点就是,这个block就不在主线程中执行啊有木有!刷新界面的操作必须要放在主线程中啊有木有!意识到这点再回过头来看网上的那些讲解包括官方Demo,都只是在reply中NSLog啊、println啊、给变量赋值啊,让我抄的时候完全忽视线程这个东西。。。。

  接下来就容易解决了,要不就定义一个是否验证成功的BOOL flag,在reply里判断赋值,然后紧跟着在方法外判断flag来进行下一步;要不就直接点,把reply里的操作放到主线程里,形如

 1 [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
 2                 localizedReason:@"使用touch ID来打开" 
3
reply:^(BOOL success, NSError *authenticationError) { 4 dispatch_async(dispatch_get_main_queue(), ^{ 5 if (success) { 6 //push 7 } else { 8 //弹出输入框 9 } 10 }); 11 }];

 

posted @ 2014-11-30 15:48  St·主宰  阅读(1322)  评论(0编辑  收藏  举报