首页 > 解决方案 > 使用 swift 使 DispatchQueue 异步崩溃

问题描述

您好,以下代码为我生成此异常,此应用程序连接到远程 node.js api 休息服务器并获取设置应用程序的值。这些值用于基于对 node.js 进行的其余调用构建自定义菜单 这些值通过返回调用验证 boolean 类型值 奇怪的是它会在线程上生成应用程序崩溃

错误:

Main Thread Checker: UI API called on a background thread: -..
2019-03-19 15:52:03.255375+0100 myapp[441:34081] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 441, TID: 34081, Thread name: (none), Queue name: com.apple.root.user-interactive-qos, QoS: 33
Backtrace:
4   myapp                               0x00000001005ca3ac $S5myapp8DatabaseC12GetServerURLSSyF + 112
5   myapp                               0x00000001005c66a4 $S5myapp4JSONC15GetSingleString6Router10ValueArray10completionySS_SDySSypGySSctF + 608
6   myapp                               0x0000000100617a08 $S5myapp9UserModelC16VerificaPermesso09TipologiaE010completionySS_ySSctFyycfU_ + 456
7   myapp                               0x0000000100566510 $SIeg_IeyB_TR + 52
8   libdispatch.dylib                   0x00000001017f7824 _dispatch_call_block_and_release + 24
9   libdispatch.dylib                   0x00000001017f8dc8 _dispatch_client_callout + 16
10  libdispatch.dylib                   0x000000010180a330 _dispatch_root_queue_drain + 716
11  libdispatch.dylib                   0x000000010180abc8 _dispatch_worker_thread2 + 156
12  libsystem_pthread.dylib             0x000000018404d17c _pthread_wqthread + 472
13  libsystem_pthread.dylib             0x000000018404fcec start_wqthread + 4

代码:

DispatchQueue.main.async {
            //Controllo permesso accesso cantieri
            self.u = User()


            //Controllo permesso accesso Clienti
            self.u.VerificaPermesso(TipologiaPermesso: "clienti", completion: { result in
                DispatchQueue.main.async {
                    if(result == "false") {
                        viewControllerList.remove(at: 4)
                        self.viewControllers = viewControllerList
                    }
                }
            });

            //Controllo permesso accesso Articoli
            self.u.VerificaPermesso(TipologiaPermesso: "articoli", completion: { result in
                DispatchQueue.main.async {
                    if(result == "false") {
                        viewControllerList.remove(at: 2)
                        self.viewControllers = viewControllerList
                    }
                }
            });

            //Controllo permesso accesso Magazzino
            self.u.VerificaPermesso(TipologiaPermesso: "magazzino", completion: { result in
                DispatchQueue.main.async {
                    if(result == "false") {
                        viewControllerList.remove(at: 5)
                        self.viewControllers = viewControllerList
                    }
                }
            });

            self.u.VerificaPermesso(TipologiaPermesso: "cantieri", completion: { result in
                DispatchQueue.main.async {
                    if(result == "false") {
                        viewControllerList.remove(at: 1)
                        self.viewControllers = viewControllerList
                    }
                }
            });


        }

获取服务器网址代码:

func GetServerURL() -> String {

        let appDelegate = UIApplication.shared.delegate as! AppDelegate

        let context = appDelegate.persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Setup")
        request.returnsObjectsAsFaults = false;
        do {
            let result = try context.fetch(request)
            if result.count > 0
                {
                for result in result as! [NSManagedObject] {
                    if let server = result.value(forKey: "server")as? String
                        {
                        self.serverSet = server

                    }

                    if let port = result.value(forKey: "port") as? Int32
                        {
                        self.portSet = "\(port)"
                    }
                }
            }
        }
        catch {
            print("Errore caricamento Parametri DB \(error)")

        }
        var ret = "\(serverSet):\(portSet)"
        if(serverSet == "" || portSet == "") {
            ret = ""
        }
        return ret

    }

标签: swift

解决方案


根据您内部的崩溃日志,myapp.Database.GetServerURL您尝试访问UIApplication.shared.delegate哪个是 UIKit api,应该在主线程上执行。
可能的解决方案:

  • 将此调用包装在DispatchQueue.main.sync { ... }.
    这将解决您的错误,但代码异味和设计错误将继续存在,并可能在未来再次打击您
  • 将此代码从AppDelegate模型依赖层移动。
    由于它是与数据库相关的调用,请考虑将其移动到可能是单例的单独数据库服务中(DB 是可能使用单例的好例子)

推荐阅读