如何正确使用信号灯同步 Alamofire 请求 Swift4 的主线程?

Posted

技术标签:

【中文标题】如何正确使用信号灯同步 Alamofire 请求 Swift4 的主线程?【英文标题】:How make correctely main thread on using sempanhores to sync Alamofire requests Swift4? 【发布时间】:2018-03-23 18:17:02 【问题描述】:

我正在使用信号量在 AlamofireXMLRPC 上同步我的请求。所以我的功能是:

let semaphore = DispatchSemaphore(value: 0)
for i in idsCloud 
            if !idsLocal.contains(i) 
                count += 1
                print("\n---->O ID: \(i) NÃO CONSTA NO BANCO LOCAL! <----\n")
                // se o id nao consta no banco local, deve inseri-lo
                OdooService.getProductByIdFromOdoo(id: i,successBlock:  (p) in
                    CoreDataHandler.saveProduct(p: p)
                    semaphore.signal()
                , failureBlock:  (erro) in
                    print(erro)
                )

                semaphore.wait()
            
    


static func getProductByIdFromOdoo( id : Int, successBlock: @escaping (_ params : [String:Any]) -> Void, failureBlock: @escaping (_ params : String) -> Void) 
        if !checkOdooConn() 
            failureBlock("Falha na conexão com o Odoo")
            return
        

        let options = ["fields": fieldsProducts] as [String:Any]
        let params = [OdooAuth.db,OdooAuth.uid,OdooAuth.password,"product.template","search_read",[[["id","=",id]]],options] as [Any]

        print("start request...")
        AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params).responseXMLRPC(queue: DispatchQueue.global(qos: .background)) 
            (response: DataResponse<XMLRPCNode>) -> Void in
            switch response.result 
            case .success( _):
                let str = String(data: response.data!, encoding: String.Encoding.utf8) as String!
                let options = AEXMLOptions()
                let pdict = strToDict(str: str!,options: options)
                successBlock(pdict.first!)
                break
            case .failure(let error):
                failureBlock(error.localizedDescription)
                break
             // fim switch
         // fim request

    

在我的“for i in idsCloud”的第一次迭代中,我在控制台上收到一条奇怪的消息。

=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 30310, TID: 1868520, Thread name: (none), Queue name: com.apple.root.background-qos, QoS: 9
Backtrace:
4   OdooVendas                          0x00000001082d184e _T010OdooVendas15CoreDataHandlerC10getContext33_C78C41DC1F74DDA11E962327A9344CC5LLSo015NSManagedObjectG0CyFZ + 94
5   OdooVendas                          0x00000001082d1951 _T010OdooVendas15CoreDataHandlerC11saveProductys10DictionaryVySSypG1p_tFZ + 33
6   OdooVendas                          0x00000001082d588c _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_ + 60
7   OdooVendas                          0x00000001082d5aaa _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_TA + 58
8   OdooVendas                          0x00000001082f6cb1 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_ + 1697
9   OdooVendas                          0x00000001082f6f62 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_TA + 114
10  AlamofireXMLRPC                     0x00000001087e052d _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TR + 173
11  AlamofireXMLRPC                     0x00000001087e1092 _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TRTA + 66
12  Alamofire                           0x0000000108686819 _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_ + 905
13  Alamofire                           0x000000010868f08e _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_TA + 110
14  Alamofire                           0x000000010863f269 _T0Ix_IyB_TR + 41
15  libdispatch.dylib                   0x000000010e1bc2f7 _dispatch_call_block_and_release + 12
16  libdispatch.dylib                   0x000000010e1bd33d _dispatch_client_callout + 8
17  libdispatch.dylib                   0x000000010e1c93a2 _dispatch_root_queue_drain + 1444
18  libdispatch.dylib                   0x000000010e1c8da0 _dispatch_worker_thread3 + 132
19  libsystem_pthread.dylib             0x000000010e6881ca _pthread_wqthread + 1387
20  libsystem_pthread.dylib             0x000000010e687c4d start_wqthread + 13
2018-03-23 15:06:48.237961-0300 OdooVendas[30310:1868520] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 30310, TID: 1868520, Thread name: (none), Queue name: com.apple.root.background-qos, QoS: 9
Backtrace:
4   OdooVendas                          0x00000001082d184e _T010OdooVendas15CoreDataHandlerC10getContext33_C78C41DC1F74DDA11E962327A9344CC5LLSo015NSManagedObjectG0CyFZ + 94
5   OdooVendas                          0x00000001082d1951 _T010OdooVendas15CoreDataHandlerC11saveProductys10DictionaryVySSypG1p_tFZ + 33
6   OdooVendas                          0x00000001082d588c _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_ + 60
7   OdooVendas                          0x00000001082d5aaa _T010OdooVendas15CoreDataHandlerC12syncProductsyyFZys10DictionaryVySSypGcfU1_TA + 58
8   OdooVendas                          0x00000001082f6cb1 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_ + 1697
9   OdooVendas                          0x00000001082f6f62 _T010OdooVendas0A7ServiceC018getProductByIdFromA0ySi2id_ys10DictionaryVySSypGc12successBlockySSc07failureL0tFZy9Alamofire12DataResponseVy0N6XMLRPC10XMLRPCNodeVGcfU_TA + 114
10  AlamofireXMLRPC                     0x00000001087e052d _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TR + 173
11  AlamofireXMLRPC                     0x00000001087e1092 _T09Alamofire12DataResponseVy0A6XMLRPC10XMLRPCNodeVGIxx_AGIxi_TRTA + 66
12  Alamofire                           0x0000000108686819 _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_ + 905
13  Alamofire                           0x000000010868f08e _T09Alamofire11DataRequestC8responseACXDSo13DispatchQueueCSg5queue_x0D10SerializeryAA0B8ResponseVy16SerializedObjectQzGc17completionHandlertAA0biH8ProtocolRzlFyycfU_yycfU_TA + 110
14  Alamofire                           0x000000010863f269 _T0Ix_IyB_TR + 41
15  libdispatch.dylib                   0x000000010e1bc2f7 _dispatch_call_block_and_release + 12
16  libdispatch.dylib                   0x000000010e1bd33d _dispatch_client_callout + 8
17  libdispatch.dylib                   0x000000010e1c93a2 _dispatch_root_queue_drain + 1444
18  libdispatch.dylib                   0x000000010e1c8da0 _dispatch_worker_thread3 + 132
19  libsystem_pthread.dylib             0x000000010e6881ca _pthread_wqthread + 1387
20  libsystem_pthread.dylib             0x000000010e687c4d start_wqthread + 13

奇怪的是一切正常,但我担心这条消息,我不知道我是否做错了什么。我不知道如何快速处理队列,但这段代码似乎解决了我的问题。 我使用 CoreData 来管理我的数据库。

【问题讨论】:

日志出现在哪一行? CoreDataHandler.saveProduct 有一些 UI 更新吗?标签、进度条等? 不,没有 UI。只有一个按钮来调用func。我用线条的图像进行了编辑。 【参考方案1】:

你不能在后台线程上调用 UIKit 方法,所以你不能访问UIApplication.delegate(这是一个 UIKit 方法)。这是您永远不应在应用程序委托中存储全局变量的众多原因之一。创建一个单独的单例,或者在需要的地方传递 viewContext。但不要在应用委托中存储任何内容。

也就是说,您也不应该在这里使用信号量。信号量几乎从来都不是正确的工具。即使您需要同步,您几乎总是应该使用 DispatchGroup,而不是 Semaphore。

如果您需要序列化调用,则让每个完成处理程序调用下一个。

如果您可以并行执行调用,则使用 DispatchGroup 并在其上使用 .notify 方法来安排在所有调用完成后执行的操作。 (对于每个网络调用,添加一个group.enter(),完成后,调用group.leave()。)

【讨论】:

我编辑并开始使用 DispatchGroup,但仅在调用请求之前group.enter(),在成功或失败块上使用group.leave(),在请求下方使用group.wait()。我创建了一个 Singleton 来获取上下文,但消息保留警告我只能在主线程上使用,并建议使用 DispatchQueue.main.async 但我不知道在哪里写这个。 "但消息保留警告我只能在主线程上使用。"只在主线程上使用什么?另外,你确定在非主线程上调用group.wait() 吗?如果你阻塞了主线程,你的程序就会崩溃。通常你想使用group.notify(),而不是group.wait() 我很难理解,我去创建另一个项目并用其他问题的上下文提出另一个问题。

以上是关于如何正确使用信号灯同步 Alamofire 请求 Swift4 的主线程?的主要内容,如果未能解决你的问题,请参考以下文章

将 Alamofire 请求转换为同步?

使用 Alamofire 的同步请求

如何在 alamofire 中同步上传图片?

多个网站的多个 Alamofire 请求的正确模型

Swift:链接多个网络请求,Alamofire

调试 Alamofire 请求