Reputation: 437
I have an NetworkRequest class, where all my Alamofire requests are made:
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()
}
}
}
And I need to cancel previous downloadData request, when the new one starts, tried to cancel using currentRequest?.cancel(), but it doesn't help.
Already tried to cancelOperations using NSOperationsBlock, but it doesn't cancels current operation.
I block UI now, so that user can't send another request. But this is not correct, causes some errors later.
Upvotes: 11
Views: 15793
Reputation: 2194
For who using AF.request AF.Session.getTasksWithCompletionHandler
or getAllTasks(completionHandler: <#T##([URLSessionTask]) -> Void#>)
always returns empty so i found a solution to cancel previous task by storing previous task instance and then checking if it's retrying to same request, if it's contains same url cancelling stored DataRequest
by calling DataRequestInstance.cancel()
For example:
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)
}
}
Upvotes: 0
Reputation: 437
Found needed solution:
func stopAllSessions() {
Alamofire.Manager.sharedInstance.session.getAllTasksWithCompletionHandler { tasks in
tasks.forEach { $0.cancel() }
}
}
Update for Alamofire 5
func stopAllSessions() {
AF.session.getTasksWithCompletionHandler { (sessionDataTask, uploadData, downloadData) in
sessionDataTask.forEach { $0.cancel() }
uploadData.forEach { $0.cancel() }
downloadData.forEach { $0.cancel() }
}
}
Upvotes: 2
Reputation: 493
Swift 5
To cancel all requests use
Alamofire.Session.default.session.getTasksWithCompletionHandler({ dataTasks, uploadTasks, downloadTasks in
dataTasks.forEach { $0.cancel() }
uploadTasks.forEach { $0.cancel() }
downloadTasks.forEach { $0.cancel() }
})
To cancel a request with a particular url use
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()
}
}
})
Upvotes: 1
Reputation: 2383
Now on Alamofire
4 the Alamofire.Manager.sharedInstance.session
is not available you should use this solution:
let sessionManager = Alamofire.SessionManager.default
sessionManager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
dataTasks.forEach { $0.cancel() }
uploadTasks.forEach { $0.cancel() }
downloadTasks.forEach { $0.cancel() }
}
and if you want to cancel (suspend, resume) a particular request you can check the request url in your .forEach
block like this:
dataTasks.forEach {
if ($0.originalRequest?.url?.absoluteString == url) {
$0.cancel()
}
}
Upvotes: 23
Reputation: 1291
If you want to cancel the request, you need to trace the requests made and try to cancel it. You can store it in an array and cancel every previous request stored.
In your code you create a request:
let request = Alamofire.request(.GET, url, headers: headers)
but you try to cancel the currentRequest?.cancel()
that is never valued.
Upvotes: 0