почему мое приложение все еще зависает, хотя я использую Alamofire, чтобы сделать запрос? - PullRequest
0 голосов
/ 13 апреля 2019

Я новичок в программировании, но обычно у меня нет проблем с запросом на получение данных JSON с сервера.

Я пробовал подобную тему здесь: Сетевые вызовы Alamofire не выполняются в фоновом потоке но решение не решает мою проблему!

поэтому я хочу реализовать разбиение на страницы, чтобы, когда пользователь достигнет нижней части экрана, я отправил запрос на сервер.

но, к сожалению, хотя я могу получить данные JSON с сервера, но это приведет к зависанию приложения. кажется, что это не выполняется в фоновом режиме (по-прежнему в основном потоке).

но я не понимаю почему. Я предполагаю, что если я использую Alamofire для выполнения запроса, он автоматически выполнит его асинхронно. потому что обычно я делаю запрос на viewDidLoad или viewWillAppear и мое приложение никогда не зависает.

вот код, срабатывающий, когда представление прокрутки достигает дна:

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

что здесь не так?

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Я думаю, что причина не связана с потоками.Вы не обрабатываете блок завершения правильно во всех случаях.В случае успеха вы работаете только с двумя сценариями, т.е. когда successStatus равен либо 1, либо 0.Что произойдет, если это не один из двух?Следовательно, вы должны добавить блок 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)
    }
0 голосов
/ 13 апреля 2019

Завершение запроса Alamofire будет выполнено в основном потоке по умолчанию. Если ваш ответ от сервера довольно велик, то выполнение этих операций JSON может быть довольно дорогим и привести к некоторым пропаданиям кадров. Alamofire позволяет установить очередь завершения, вызывая ее следующим образом:

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