You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS应用拒绝通讯录权限时崩溃问题求助

iOS通讯录权限拒绝时应用偶尔崩溃问题

开发的iOS应用在用户登录时请求通讯录权限,点击「允许」时功能正常,但点击「不允许」时应用偶尔崩溃,崩溃位置在创建UIAlertController的代码处,报错提示:

Assert Cannot be called with asCopy = NO on non-main thread

相关代码

- (BOOL) checkContactPermission {
__block BOOL authorized = NO;

// VAMOS A SOPORTAR A PARTIR DE IOS 9 POR LO QUE NO NECESITAMOS COMPROBARLO
// if ([CNContactStore class]) { }; //ios9 or later
CNEntityType entityType = CNEntityTypeContacts;

// Si no hemos pedido permiso de acceso antes lo pedimos
if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined) {
    
    CNContactStore * contactStore = [[CNContactStore alloc] init];
    [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if(granted){
            NSLog(@"Contacts access Granted");
            authorized = YES;
        }
        // Si el usuario no nos da permiso mostramos un alert
        else {
            NSLog(@"Contacts access Denied");
            
            UIAlertController *alert = [UIAlertController
                                        alertControllerWithTitle:@"No se puede acceder a los contactos"
                                        message:@"La App necesita permiso de acceso a los contactos para mostrar el nombre de cada contacto en el listado de llamadas de la app."
                                        preferredStyle: UIAlertControllerStyleAlert];
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                             handler:^(UIAlertAction * action){
                                                                 // Ok action example
                                                             }];
            [alert addAction:okAction];
            
            // Muestro el alert en el hilo principal
            dispatch_async(dispatch_get_main_queue(), ^{
                [[[[UIApplication sharedApplication]keyWindow]rootViewController]presentViewController:alert
                                                                                              animated:YES
                                                                                            completion:nil];
            });
        }
    }];
}
else if( [CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusAuthorized) {
    NSLog(@"Contacts access Authorized");
    authorized = YES;
}
return authorized;
}

Xcode线程信息

  • 正常情况(OK)-> Thread 25
    Thread 25 Queue : com.apple.root.default-qos (concurrent)

    #0  0x00000001034c29d1 in __43-[GetContactsPlugin checkContactPermission]_block_invoke at /Users/vyorkmur/Documents/APP MiJazztel/Alicante/cordova10/mijazztel-application-typescript/platforms/ios/Mi Jazztel/Plugins/com.viewnext.plugin.getcontacts/GetContactsPlugin/GetContactsPlugin.m:198
    
  • 崩溃情况(KO)-> Thread 4
    Thread 4 Queue : com.apple.root.default-qos (concurrent)

    #23 0x0000000108340a19 in __43-[GetContactsPlugin checkContactPermission]_block_invoke at /Users/vyorkmur/Documents/APP MiJazztel/Alicante/cordova10/mijazztel-application-typescript/platforms/ios/Mi Jazztel/Plugins/com.viewnext.plugin.getcontacts/GetContactsPlugin/GetContactsPlugin.m:200
    

问题原因

CNContactStore的权限请求回调completionHandler运行在后台线程,而UIKit的所有操作(包括创建UIAlertController、UIAlertAction这类UI组件)必须在主线程执行。当前代码仅把弹窗展示操作放到主线程,但弹窗的创建、配置过程仍在后台线程,触发了系统断言导致崩溃。

解决方案

将弹窗的创建、配置及展示的全部逻辑,都移至dispatch_async(dispatch_get_main_queue(), ^{...})代码块内,确保所有UI操作都在主线程执行。

修改后的核心代码片段:

[contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
    if(granted){
        NSLog(@"Contacts access Granted");
        authorized = YES;
    }
    // Si el usuario no nos da permiso mostramos un alert
    else {
        NSLog(@"Contacts access Denied");
        
        // 所有UI操作移至主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            UIAlertController *alert = [UIAlertController
                                        alertControllerWithTitle:@"No se puede acceder a los contactos"
                                        message:@"La App necesita permiso de acceso a los contactos para mostrar el nombre de cada contacto en el listado de llamadas de la app."
                                        preferredStyle: UIAlertControllerStyleAlert];
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                             handler:^(UIAlertAction * action){
                                                                 // Ok action example
                                                             }];
            [alert addAction:okAction];
            
            [[[[UIApplication sharedApplication]keyWindow]rootViewController]presentViewController:alert
                                                                                          animated:YES
                                                                                        completion:nil];
        });
    }
}];

内容的提问来源于stack exchange,提问作者Victor York

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:40:34