为啥即使我使用 Alamofire 发出请求,我的应用程序仍然冻结?

Posted

技术标签:

【中文标题】为啥即使我使用 Alamofire 发出请求,我的应用程序仍然冻结?【英文标题】:why my app still freezing even though I use Alamofire to make a request?为什么即使我使用 Alamofire 发出请求,我的应用程序仍然冻结? 【发布时间】:2019-04-13 06:59:22 【问题描述】:

我是编程新手,但我通常可以请求从服务器获取 JSON 数据。

我在这里尝试了一些类似的线程:Alamofire network calls not being run in background thread 但解决方案并没有解决我的问题!

所以我想实现分页,所以当用户到达屏幕底部时,我会向服务器发出请求。

但不幸的是,即使我可以从服务器获取 JSON 数据,但它会冻结应用程序。似乎这不是在后台执行的(仍在主线程上)。

但我不明白为什么。我假设如果我使用 Alamofire 发出请求,它会自动异步执行它。因为通常我在viewDidLoadviewWillAppear 上提出请求,而我的应用永远不会冻结。

这是滚动视图到达底部时触发的代码:

extension HomeVC : UIScrollViewDelegate 

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) 


        let currentOffset = scrollView.contentOffset.y
        let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height


            if maximumOffset - currentOffset <= 10.0 

            // load more product data when reaching the bottom of main scroll view

            pageNumberTracker += 1
            SVProgressHUD.show(withStatus: "Please Wait")

            Product.getProducts(searchType: "newest", pageNumber: pageNumberTracker, categoryID: selectedCategoryID)  (errorWhileMakingRequest, errorMessageFromServer, products) in

                if errorWhileMakingRequest != nil || errorMessageFromServer != nil 
                    SVProgressHUD.dismiss()
                    return
                



                guard let products = products else self.activityIndicator.stopAnimating(); return

                self.thirdProducts += products
                self.updateLocalDataToBeTheSameAsRealmDatabase()
                self.setThirdListProductCollectionViewHeight()
                self.thirdListProductCollectionView.reloadData()
                SVProgressHUD.dismiss()


            




        
    




这里是getProduct() 方法:

static func getProducts(searchType: String, pageNumber: Int = 0, categoryID: Int = 0, completion: @escaping(_ errorWhileMakingRequest: Error?, _ errorMessageFromServer: String?,_ productsData: [Product]?) -> Void) 

        let urlProducts = URLService.products.endPoint
        let headers = ["Content-Type": "application/x-www-form-urlencoded"]

        let parameters : [String:Any] = [
            "type": searchType,
            "language_id": 1,
            "page_number": pageNumber,
            "minPrice": 0,
            "maxPrice":10000000,
            "categories_id": categoryID
        ]

        AlamofireManager.shared.request(urlProducts,
                          method: .post,
                          parameters: parameters,
                          encoding: URLEncoding.default,
                          headers:headers)
            .validate()
            .responseJSON  response in

                switch response.result 

                case .failure(let error) :

                    completion(error,nil,nil)

                case .success(let value) :

                    let json = JSON(value)
                    let successStatus = json["success"].stringValue

                    if successStatus == "0" 
                        let errorMessage = json["message"].stringValue
                        completion(nil,errorMessage,nil)
                     else if successStatus == "1" 

                        let productsArrayJSON = json["product_data"].arrayValue
                        var productsData = [Product]()

                        for productJSON in productsArrayJSON 
                            if let productDictionary = productJSON.dictionaryObject 
                                let product = Product(dictionary: productDictionary)
                                productsData.append(product)
                             else 
                                completion(nil,nil,nil)
                                break
                            
                        

                        completion(nil,nil,productsData)



                    

                

        




    

这里是 Alamofire 管理器代码:

struct AlamofireManager 
    static let shared: SessionManager = 
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 15
        let sessionManager = Alamofire.SessionManager(configuration: configuration, delegate: SessionDelegate(), serverTrustPolicyManager: nil)
        return sessionManager
    ()

这里出了什么问题?

【问题讨论】:

Alamofire network calls not being run in background thread的可能重复 @Anand 它不能解决我的问题 你试过 GCD 让它在后台线程上运行吗? 您的请求方法不应该是GET 而不是POST。您的请求方法是method: .post 【参考方案1】:

默认情况下,Alamofire 请求的完成将在主线程上执行。如果来自服务器的响应非常大,那么执行这些 JSON 操作可能会非常昂贵并导致一些帧丢失。 Alamofire 允许您通过这样调用它来设置完成队列:

AlamofireManager.shared.request(urlProducts,
                          method: .post,
                          parameters: parameters,
                          encoding: URLEncoding.default,
                          headers:headers)
            .validate()
            .responseJSON(queue: DispatchQueue.someQueue)  response in
                 ...
            

【讨论】:

【参考方案2】:

我认为原因与线程无关。在所有情况下,您都没有正确处理完成块。如果成功,您只需要处理两种情况,即当successStatus10 时。如果两者都不是会发生什么?因此,您应该在末尾添加一个 else 块,以便在所有情况下都调用完成块。代码如下:

case .success(let value):

    let json = JSON(value)
    let successStatus = json["success"].stringValue

    if successStatus == "0" 
        let errorMessage = json["message"].stringValue
        completion(nil,errorMessage,nil)
     else if successStatus == "1" 

        let productsArrayJSON = json["product_data"].arrayValue
        var productsData = [Product]()

        for productJSON in productsArrayJSON 
            if let productDictionary = productJSON.dictionaryObject 
                let product = Product(dictionary: productDictionary)
                productsData.append(product)
             else 
                completion(nil,nil,nil)
                break
            
        

        completion(nil,nil,productsData)
    
    else 
        // Decide how you should call the completion block
        completion(xx, yy, zz)
    

【讨论】:

以上是关于为啥即使我使用 Alamofire 发出请求,我的应用程序仍然冻结?的主要内容,如果未能解决你的问题,请参考以下文章

为啥没有网络连接时 Alamofire 需要这么长时间才能超时?

如何使用操作查询发出多个 Alamofire 请求

alamofire 499 使用标头和参数发出获取请求时

如何处理网络中间请求的变化 - Alamofire

带循环的 Alamofire 同步请求

由于 TIC SSL 信任错误,无法使用 Alamofire 发出请求