如何取消之前的 Alamofire 请求?

问题描述 投票:0回答:5

我有一个 NetworkRequest 类,我所有的 Alamofire 请求都是在其中发出的:

class NetworkRequest {
    static let request = NetworkRequest()
    
    var currentRequest: Alamofire.Request?
        
    let dataManager = DataManager()
    let networkManager = NetworkReachabilityManager()
    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    
    func downloadData<T: Film>(slug: String, provider: String, section: String, dynamic: String, anyClass: T, completion: ([T]?) -> Void ) {
        var token: String = ""
        
        if LOGGED_IN == true {
            token = "\(NSUserDefaults.standardUserDefaults().valueForKey(TOKEN)!)"
        }
        
        let headers = [
            "Access": "application/json",
            "Authorization": "Bearer \(token)"
        ]
                
        let dataUrl = "\(BASE_URL)\(slug)\(provider)\(section)\(dynamic)"
        print(headers)
        print(dataUrl)
        
        if networkManager!.isReachable {
            
            currentRequest?.cancel()
            
            dispatch_async(dispatch_get_global_queue(priority, 0)) {
            
                if let url = NSURL(string: dataUrl) {
                    let request = Alamofire.request(.GET, url, headers: headers)
                    
                    request.validate().responseJSON { response in
                        switch response.result {
                        case .Success:
                            if let data = response.result.value as! [String: AnyObject]! {
                                let receivedData = self.dataManager.parseDataToFilms(data, someClass: anyClass)
                                completion(receivedData)
                            }
                            
                        case .Failure(let error):
                            print("Alamofire error: \(error)")
                            
                            if error.code == 1001 {
                                self.goToNoConnectionVC()
                            }
                            
                            print("canceled")
                        }
                        
                    }
                }
            }
        } else {
            goToNoConnectionVC()
        }
    }
}

而且我需要取消以前的 downloadData 请求,当新的 downloadData 请求开始时,尝试使用 currentRequest?.cancel() 取消,但没有帮助。

已尝试使用 NSOperationsBlock 取消操作,但它不会取消当前操作。

我现在阻止 UI,以便用户无法发送另一个请求。但这是不正确的,会导致稍后出现一些错误。

swift request alamofire
5个回答
23
投票

现在在

Alamofire
4 上
Alamofire.Manager.sharedInstance.session
不可用,您应该使用 this 解决方案:

let sessionManager = Alamofire.SessionManager.default 
sessionManager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in 
dataTasks.forEach { $0.cancel() } 
uploadTasks.forEach { $0.cancel() } 
downloadTasks.forEach { $0.cancel() } 
}

如果您想取消(暂停、恢复)特定请求,您可以检查

.forEach
块中的请求网址,如下所示:

dataTasks.forEach {
                if ($0.originalRequest?.url?.absoluteString == url) {
                    $0.cancel()
                }
            }

2
投票

找到需要的解决方案:

func stopAllSessions() {
    Alamofire.Manager.sharedInstance.session.getAllTasksWithCompletionHandler { tasks in
        tasks.forEach { $0.cancel() }
    }
}

Alamofire 5 更新

func stopAllSessions() {
    AF.session.getTasksWithCompletionHandler { (sessionDataTask, uploadData, downloadData) in
        sessionDataTask.forEach { $0.cancel() }
        uploadData.forEach { $0.cancel() }
        downloadData.forEach { $0.cancel() }
    }
}

1
投票

斯威夫特5

要取消所有请求,请使用

Alamofire.Session.default.session.getTasksWithCompletionHandler({ dataTasks, uploadTasks, downloadTasks in
        dataTasks.forEach { $0.cancel() }
        uploadTasks.forEach { $0.cancel() }
        downloadTasks.forEach { $0.cancel() }
    })

要取消具有特定 url 的请求,请使用

Alamofire.Session.default.session.getTasksWithCompletionHandler({ dataTasks, uploadTasks, downloadTasks in
    dataTasks.forEach {
            if ($0.originalRequest?.url?.absoluteString == "www.google.com") {
                $0.cancel()
            }
        
    }
    uploadTasks.forEach {
        if ($0.originalRequest?.url?.absoluteString == "www.google.com") {
            $0.cancel()
        }
    }
    downloadTasks.forEach {
        if ($0.originalRequest?.url?.absoluteString == "www.google.com") {
            $0.cancel()
        }
        
    }
})

0
投票

如果您想取消请求,您需要追踪发出的请求并尝试取消。您可以将其存储在数组中并取消之前存储的每个请求。 在您的代码中创建一个请求:

let request = Alamofire.request(.GET, url, headers: headers)
但你试图取消那些永远不被重视的
currentRequest?.cancel()


0
投票

对于使用 AF.request

AF.Session.getTasksWithCompletionHandler
getAllTasks(completionHandler: <#T##([URLSessionTask]) -> Void#>)
的人来说,总是返回空,所以我找到了一个解决方案来取消上一个任务,方法是存储上一个任务实例,然后检查它是否重试相同的请求,如果它包含相同的 url,则取消存储的
DataRequest 
致电
DataRequestInstance.cancel()

例如:

private var isRetrying = false
private var latestDataRequest: DataRequest?

typealias ServiceCompletionHandler = (Swift.Result<ExampleResponse, Error>) -> ()

func requestTokenDataWith(completionHandler: @escaping ServiceCompletionHandler) {
            
    let url = // Your service url
    let parameters = // Required parameters
    
    // Cancel first request if isn't response until now
    if isRetrying, let latestDataRequest {
        
        // Find request task that contains exact same url with new request
        // Or you can directly cancel old DataRequest without looking for url
        let sameOldRequests = latestDataRequest.tasks.compactMap({ $0.originalRequest?.url }).filter({ $0 == url })
        if sameOldRequests.isEmpty == false {
            
            // Cancel first task and release it's instance
            latestDataRequest.cancel()
            self.latestDataRequest = nil
            
            // Log error
            let error = NetworkError(
                domain: Constants.bundleId(),
                code: -1,
                type: .stillWaitingForResponse
            )
            Logger.shared.info(from: "TokenService", message: error.localizedDescription)
        }
    }
    
    // No requests already in, mark as true to block coming requests
    isRetrying = true
    
    latestDataRequest = AF.request(
        url,
        method: .post,
        parameters: params,
        encoding: URLEncoding.httpBody,
        interceptor: self
    )
    .validate(contentType: ["application/json"])
    .validate(statusCode: 200..<300)
    .responseJSON(completionHandler: { response in
        // Stop blocking incoming requests
        self?.isRetrying = false
        completionHandler(response)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.