[英]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. 我是编程新手,但我通常没有问题要求从服务器获取JSON数据。
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! 我在这里尝试了一些类似的线程: Alamofire网络调用没有在后台线程中运行,但解决方案并没有解决我的问题!
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. 但不幸的是,即使我可以从服务器获取JSON数据,但它会冻结应用程序。 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.
我假设如果我使用Alamofire发出请求,它将自动异步执行。 because usually I make a request on
viewDidLoad
or viewWillAppear
and my app never freezing. 因为通常我在
viewDidLoad
或viewWillAppear
上发出请求,我的应用程序永远不会冻结。
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 : 这是
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)
}
}
}
}
and here is the Alamofire manager code: 这里是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
}()
}
what went wrong in here ? 这里出了什么问题?
The completion of an Alamofire request will execute on the main thread by default. 默认情况下,Alamofire请求的完成将在主线程上执行。 If your response from the server is pretty big, then doing those JSON operations can be pretty expensive and cause some frame drops.
如果您对服务器的响应非常大,那么执行这些JSON操作可能会非常昂贵并导致一些帧丢失。 Alamofire allows you to set the completion queue by calling it like this:
Alamofire允许您通过调用它来设置完成队列:
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
. 如果成功,您只处理两种情况,即
successStatus
为1
或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.
因此,您应该在末尾添加一个else块,以便在所有情况下都调用完成块。 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)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.