【问题标题】:Swift app crashing when attempting to fetch contactsSwift 应用程序在尝试获取联系人时崩溃
【发布时间】:2020-07-14 15:49:31
【问题描述】:

我正在创建一个应用程序的入门部分,它可以让用户的联系人检查哪些已经有应用程序添加为朋友。我正在使用 CNContact 框架。我创建了几种方法来获取用户联系人的完整列表,检查他们是否有应用程序,并在 UITableView 中枚举它们。但是,当视图加载时,应用程序崩溃并显示错误“获取联系人时未请求属性”。我已经使用 CNContactGivenNameKey、CNContactFamilyNameKey、CNContactPhoneNumbersKey 和 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)
        }
        
    }
}

然后我调用视图控制器类中的方法:

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 数组时出错”,所以我知道该方法出了点问题,我只是不确定是什么。任何帮助表示赞赏!

编辑:异常在 3 点处引发:1 在我的 FetchedContact 初始化方法的第一行,如下所示:

init(cnContact: CNContact, numsInFirebase: [String]) {
    if cnContact.imageDataAvailable { self.image = UIImage(data: cnContact.imageData!) } 

它还指向 createFetched 联系人数组中的 let f = FetchedContact(cnContact: c, numsInFirebase: nums) 行,最后在 getNumsInFirestore 中的完成(numsInFirebase)调用。

【问题讨论】:

  • 你在哪一行得到错误?
  • 它没有给我一行,只是在 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, numsInFirebase: nums) 行,最后在 getNumsInFirestore 中的完成(numsInFirebase)调用。
  • 请在您的问题中添加其他信息 - 在 cmets 中很难阅读。

标签: swift asynchronous contacts


【解决方案1】:

开始

 let contacts = createContactArray()

将始终返回一个空数组。

这个函数在闭包之外有一个返回语句,所以会立即返回一个空数组。

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

【讨论】:

  • 这实际上不是问题——我添加了一个打印语句来查看初始化后 cnContacts 的计数是多少,它是 127,这是我正在测试的手机上的联系人数量.
  • 您在上面发布的代码不太可能发生这种情况。您设置一个空数组,调用一个异步函数,然后返回该数组。在返回时,异步函数不太可能填充数组。我不会打赌这段代码每次都返回非空结果。
猜你喜欢
  • 1970-01-01
  • 2017-01-27
  • 2015-11-13
  • 1970-01-01
  • 2016-04-04
  • 1970-01-01
  • 2021-06-03
  • 1970-01-01
  • 2017-07-09
相关资源
最近更新 更多