Сбой приложения Swift при попытке получить контакты - PullRequest
0 голосов
/ 14 июля 2020

Я создаю входящую в систему часть приложения, которая заставляет контакты пользователя проверять, у кого уже есть приложение для добавления в друзья. Я использую фреймворк 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)
        }
        
    }
}

Затем я вызываю методы в классе контроллера представления:

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!) } 

Это также указывает на строка let f = FetchedContact (cnContact: c, numsInFirebase: nums) в массиве контактов createFetched и, наконец, при моем завершении вызова (numsInFirebase) в getNumsInFirestore.

1 Ответ

0 голосов
/ 14 июля 2020

Для начала с

 let contacts = createContactArray()

всегда будет возвращать пустой массив.

Эта функция имеет оператор возврата за пределами замыкания, поэтому немедленно возвращает пустой массив.

Измените createContactArray, чтобы использовать обработчик завершения, как и другие функции, которые вам нужны для заполнения контактов изнутри замыкания.

...