尝试获取联系人时Swift应用程序崩溃

尝试获取联系人时Swift应用程序崩溃,swift,asynchronous,contacts,Swift,Asynchronous,Contacts,我正在创建一个应用程序的入职部分,该部分可以让用户的联系人检查哪些人已经将该应用程序添加为好友。我正在使用CNContact框架。我创建了几种方法,用于获取用户联系人的完整列表,检查他们是否拥有应用程序,并在UITableView中枚举他们。但是,当视图加载时,应用程序崩溃,错误为“获取联系人时未请求属性”。我已使用键CNContactGivenNameKey、CNContactFamilyNameKey、CNContactPhoneNumbersKey、ad CNContactImageDat

我正在创建一个应用程序的入职部分,该部分可以让用户的联系人检查哪些人已经将该应用程序添加为好友。我正在使用CNContact框架。我创建了几种方法,用于获取用户联系人的完整列表,检查他们是否拥有应用程序,并在UITableView中枚举他们。但是,当视图加载时,应用程序崩溃,错误为“获取联系人时未请求属性”。我已使用键CNContactGivenNameKey、CNContactFamilyNameKey、CNContactPhoneNumbersKey、ad CNContactImageDataKey发出获取请求。我在这里包含了我的所有代码:

import Foundation
import Contacts
import PhoneNumberKit

struct ContactService {
    
    static func createContactArray() -> [CNContact] {
            
        var tempContacts = [CNContact]()
            
        let store = CNContactStore()
        store.requestAccess(for: .contacts) { (granted, error) in
            if let _ = error {
                print("failed to request access to contacts")
                return
            }
            if granted {
                let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey]
                let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
                request.sortOrder = CNContactSortOrder.familyName
                do {
                    try store.enumerateContacts(with: request, usingBlock: { (contact, stop) in
                    tempContacts.append(contact)
                    })
                } catch {
                    print("unable to fetch contacts")
                }
                
                print("created contact list")
            }
            
        }
            
        return tempContacts
            
    }
    
    static func createFetchedContactArray(contactArray: [CNContact], completion: @escaping ([FetchedContact]?) -> Void) -> Void {
        
        var temp = [FetchedContact]()
        getNumsInFirestore { (nums) in
            if let nums = nums {
                for c in contactArray {
                    let f = FetchedContact(cnContact: c, numsInFirebase: nums)
                    temp.append(f)
                }
                return completion(temp)
            } else {
                print("Error retrieving numbers")
            }
        }
        
        return completion(nil)
        
    }
    
    static func getNumsInFirestore(_ completion: @escaping (_ nums : [String]?) -> Void ) -> Void {
        var numsInFirebase = [String]()
        let db = FirestoreService.db

        db.collection(Constants.Firestore.Collections.users).getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting user documents: \(err)")
                completion(nil)
            } else {
                for doc in querySnapshot!.documents {
                    let dict = doc.data()
                    numsInFirebase.append(dict[Constants.Firestore.Keys.phone] as! String)
                }
                completion(numsInFirebase)
            }
        }
    }
    
    static func getPhoneStrings(contact: CNContact) -> [String] {
        
        var temp = [String]()
        
        let cnPhoneNums = contact.phoneNumbers
        for n in cnPhoneNums {
            temp.append(n.value.stringValue)
        }
        
        return temp
        
    }
    
    static func hasBump(contact: CNContact, completion: @escaping (_ h: Bool) -> Void ) -> Void {
        
        let contactNums = ContactService.getPhoneStrings(contact: contact)
        ContactService.getNumsInFirestore { (nums) in
            if let nums = nums {
                return completion(contactNums.contains(where: nums.contains))
            } else {
                print("Error retrieving numbers from firestore")
                return completion(false)
            }
        }
    }
    
    static func anyContactsWithBump(completion: @escaping (_ yes: Bool) -> Void) {
        
        let contacts = createContactArray()
        var tempBool = false
        let workgroup = DispatchGroup()
        
        for c in contacts {
            workgroup.enter()
            hasBump(contact: c) { (has) in
                if has {
                    tempBool = true
                }
                workgroup.leave()
            }
        }
        
        workgroup.notify(queue: .main) {
            completion(tempBool)
        }
        
    }
}
然后调用view controller类中的方法:

import UIKit
import Contacts
import FirebaseDatabase
import Firebase
import FirebaseFirestore

class AddContactsVC: UIViewController {

    var fetchedContactsWithBump: [FetchedContact] = []
    
    override func viewDidLoad() {
        
        let cnContacts = ContactService.createContactArray()
        
        var contactsWithBump = [CNContact]()
        
        let workgroup = DispatchGroup()
        
        for contact in cnContacts {
            workgroup.enter()
            ContactService.hasBump(contact: contact) { (has) in
                if has {
                    contactsWithBump.append(contact)
                }
                workgroup.leave()
            }
            
        }
        
        workgroup.notify(queue: .main) {
            print("Number of contacts with Bump: \(contactsWithBump.count)")
            ContactService.createFetchedContactArray(contactArray: contactsWithBump) { (fetchedContacts) in
                if let fetchedContacts = fetchedContacts {
                    self.fetchedContactsWithBump = fetchedContacts
                } else {
                    print("Error creating fetchedContacts array.")
                }
            }
        }
我在控制台中还收到消息“创建fetchedContacts数组时出错”,因此我知道该方法出现了一些问题,我只是不确定是什么问题。感谢您的帮助

编辑:异常在我的FetchedContact init方法的第一行的3个点抛出:1,如下所示:

init(cnContact: CNContact, numsInFirebase: [String]) {
    if cnContact.imageDataAvailable { self.image = UIImage(data: cnContact.imageData!) } 
它还指向createFetched联系人数组中的行let f=FetchedContact(cnContact:c,numsInFirebase:nums),最后指向GetNumsInfireRestore中的my completion(numsInFirebase)调用。

 let contacts = createContactArray()
将始终返回空数组

此函数在闭包外有一个return语句,因此将立即返回一个空数组


将createContactArray更改为使用完成处理程序,就像您必须从闭包内部填充联系人的其他函数一样。

在哪一行出现错误?它没有给我一行,只是在AppDelegate类的顶部这样说。请尝试添加“异常断点”在您的项目中。确定它在3点显示异常:1在我的FetchedContact init方法的第一行,如下所示:``init(cnContact:cnContact,numsInFirebase:[String]){if cnContact.imageDataAvailable{self.image=UIImage(data:cnContact.imageData!)}```它还指向createFetched联系人数组中的行
let f=FetchedContact(cnContact:c,numsfirebase:nums)
,最后是在我完成时(numsfirebase)打电话到getNumsInFirestore。请在您的问题中添加其他信息-在评论中很难阅读。这实际上不是问题-我添加了一个打印语句以查看初始化后cnContacts的计数,它是127,这是我正在测试的手机上的联系人数。这在您在上面发布的代码。您设置了一个空数组,调用了一个异步函数,然后返回数组。在返回时,异步函数不太可能已经填充了数组。我打赌这段代码不会每次都返回一个非空的结果。