CXCallObserver 无法正常工作,并且当 运行 多个应用程序(包括联系人图像数据时)时应用程序崩溃

CXCallObserver is not working properly and App getting crash when running the app more than one (when includes contacts image data)

我面临两个主要问题,第一个是: 1. 我正在尝试检测来电、去电、拨号,我正在使用此代码:

import UIKit
import CoreTelephony
import CallKit


class ViewController: UIViewController,CXCallObserverDelegate {


   let  callObserver = CXCallObserver()

    var seconds = 0
    var timer = Timer()

    override func viewDidLoad() {
        super.viewDidLoad()
        callObserver.setDelegate(self, queue: nil)

    }



    override func viewWillAppear(_ animated: Bool) {
        print("viewWillAppear \(seconds)")


    }


  fileprivate  func runTimer(){

        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: true)

    }

    func updateTimer() {
        seconds += 1
        print("Seconds \(seconds)")
    }



    @IBAction func callButton(_ sender: UIButton) {


        if let url = URL(string: "tel://\(12345879)"){

            UIApplication.shared.open(url, options: [:], completionHandler: nil)

        }



    }


    func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
        if call.hasEnded == true {
            print("Disconnected")
            seconds = 0
            self.timer.invalidate()

        }
        if call.isOutgoing == true && call.hasConnected == false  {
            print("Dialing call")
            self.runTimer()

        }
        if call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false {
            print("Incoming")
        }

        if call.hasConnected == true && call.hasEnded == false {
            print("Connected")
        }
    }



}

当我拨打一个号码时它工作正常,它显示 "Dialling" 但是当我挂断电话时它显示 "Disconnected" 然后又显示 "Dialing" 状态。

  1. 另一个问题是,当我从设备中获取所有联系人信息时,当我不获取图像数据时它工作正常,但当我获取联系人图像时它第一次工作正常。然后如果我 运行 它再次应用变慢。然后接下来它崩溃显示在展开值时发现 nil。

我在 AppDelegate 中写了我的联系人数据获取功能。它在应用程序启动时调用。这是代码:

func fetchContactList(){
        let loginInformation = LoginInformation()
        var contactModelData: [ContactsModel] = []
        var profileImage : UIImage?

        let store = CNContactStore()
        store.requestAccess(for: .contacts, completionHandler: {
            granted, error in

            guard granted else {
                let alert = UIAlertController(title: "Can't access contact", message: "Please go to Settings -> MyApp to enable contact permission", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                self.window?.rootViewController?.present(alert, animated: true, completion: nil)
                return
            }


            let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey, CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactThumbnailImageDataKey,CNContactThumbnailImageDataKey] as [Any]
            let request = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
            var cnContacts = [CNContact]()

            do {
                try store.enumerateContacts(with: request){
                    (contact, cursor) -> Void in
                    cnContacts.append(contact)
                }
            } catch let error {
                NSLog("Fetch contact error: \(error)")
            }

            for contact in cnContacts {
                let fullName = CNContactFormatter.string(from: contact, style: .fullName) ?? "No Name"

                var phoneNumberUnclean : String?
                var labelofContact : String?
                var phoneNumberClean: String?

                for phoneNumber in contact.phoneNumbers {
                    if let number = phoneNumber.value as? CNPhoneNumber,
                        let label = phoneNumber.label {
                        let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
                        print("fullname \(fullName), localized \(localizedLabel), number \(number.stringValue)")
                        phoneNumberUnclean = number.stringValue
                        labelofContact = localizedLabel
                    }



                }


                if let imageData = contact.imageData {
                    profileImage = UIImage(data: imageData)
                    print("image \(String(describing: UIImage(data: imageData)))")
                } else {
                    profileImage = UIImage(named: "user")

                }




                self.contactModelData.append(ContactsModel(contactName: fullName, contactNumber:phoneNumberUnclean!, contactLabel: labelofContact!, contactImage: profileImage!, contactNumberClean: phoneNumberUnclean!))





            }
            self.loginInformation.saveContactData(allContactData: self.contactModelData)

        })



    }

我已经用这个解决了这两个问题: 对于第一个,当我断开呼叫时,如果不幸的是它再次转到 "Dialling" 选项,我检查了 "seconds" 变量的值,如果它在 "Dialing" 中大于 0,则使线程无效。

第二个问题: 我使用了 Dispatch.async.main 后台线程并拍摄了缩略图