简体   繁体   中英

why my app still freezing even though I use Alamofire to make a request?

I am new in programming, but I usually I have no issue to make request to get JSON data from server.

I have tried some similar thread in here: Alamofire network calls not being run in background thread but the solution doesn't solve my problem!

so I want to implement pagination, so when the user reach bottom of the screen, then I will make a request to the server.

but unfortunately, even though I can get the JSON data from server, but it will freeze the app. it seems that this is not performed in the background (still on the main thread).

but I don't understand why. I assume that if I use Alamofire to make a request, it will automatically perform it asynchronously. because usually I make a request on viewDidLoad or viewWillAppear and my app never freezing.

here is the code triggered when the scroll view reach the bottom:

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()


            }




        }
    }



}

here is the getProduct() method :

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)



                    }

                }

        }




    }

and here is the Alamofire manager code:

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

what went wrong in here ?

The completion of an Alamofire request will execute on the main thread by default. If your response from the server is pretty big, then doing those JSON operations can be pretty expensive and cause some frame drops. Alamofire allows you to set the completion queue by calling it like this:

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

I think the reason is not related to the threading. You are not handling the completion block properly in all cases. In case of success you are handling just two scenarios ie when successStatus is either 1 or 0 . What happens if it is neither of the two? Hence you should add an else block at the end so that the completion block gets called in all cases. Here's the code:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM