问题
I am uploading images on server via Alamofire.upload
as multipart data. Unlike Alamofire.request
it's not returning Request
object, which I usually use to cancel requests.
But it's very reasonable to be able to cancel such a consuming requests like uploading. What are the options for this in Alamofire?
回答1:
Using the Uploading MultiPartFormData example from the Alamofire README:
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
Here, upload.responseJSON
returns a Request
, which should allow you to assign it to something for cancellation later. For example:
let request = upload.responseJSON { ...
...
request.cancel()
回答2:
I'm afraid you can't, according to the Alamofire source code the upload
function returns an Request
type in all of its overloads except in these that support MultipartFormData see the following code:
// MARK: MultipartFormData
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter method: The HTTP method.
- parameter URLString: The URL string.
- parameter headers: The HTTP headers. `nil` by default.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
method: Method,
URLString: URLStringConvertible,
headers: [String: String]? = nil,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
method,
URLString,
headers: headers,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
/**
Creates an upload request using the shared manager instance for the specified method and URL string.
- parameter URLRequest: The URL request.
- parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
- parameter encodingMemoryThreshold: The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
by default.
- parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
*/
public func upload(
URLRequest: URLRequestConvertible,
multipartFormData: MultipartFormData -> Void,
encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
{
return Manager.sharedInstance.upload(
URLRequest,
multipartFormData: multipartFormData,
encodingMemoryThreshold: encodingMemoryThreshold,
encodingCompletion: encodingCompletion
)
}
It's recommended when you are writing client-side code, use multipart/form-data
when your form includes any <input type="file">
elements.
So if you want to just upload an image to the server you can use the another upload
function overloads that returns an Request
object and you can cancel it like in this ways proposed in the Alamofire documentation:
let fileURL = NSBundle.mainBundle().URLForResource("Default", withExtension: "png")
ler request =Alamofire.upload(.POST, "https://httpbin.org/post", file: fileURL)
// request.cancel()
I hope this help you.
回答3:
It's possible to prepare a closure, and transfer a request out of "encodingCompletion"
class NetworkManager {
private var closure: ((Request)->())?
func startUpload() {
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
self.closure?(upload)
upload.responseJSON { response in
debugPrint(response)
uploadRequest = nil
}
case .Failure(let encodingError):
print(encodingError)
}
}
)
}
}
回答4:
In my case I created "sessionManager" instance in my API class and assigned Alamofire's session manager with configuration to it.
var sessionManager: SessionManager!
// Setup request manager
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = TimeInterval(15.0)
configuration.timeoutIntervalForRequest = TimeInterval(15.0)
sessionManager = Alamofire.SessionManager(configuration: configuration)
sessionManager.upload(multipartFormData: { multipartFormData in
// AppendMultipart parts
multipartFormData.append(metadataBodyPart, withName: PartName.Metadata, mimeType: MimeType.MultiPart)
multipartFormData.append(imageDataBodyPart, withName: PartName.Photo, mimeType: MimeType.ImageJPG)
} // ... rest of the code
Then I could create a method to cancel any current request type. Note that here "(_, uploadTasks, _)" you can also have "dataTasks" & "downloadTasks" which you can also cancel if you want "(dataTasks, uploadTasks, downloadTasks)"
func cancelUploadRequest() {
sessionManager.session.getTasksWithCompletionHandler { (_, uploadTasks, _) in
uploadTasks.forEach { $0.cancel() }
}
}
You can also have smth like this:
func cancel(request: CancelRequestType) {
sessionManager.session.getTasksWithCompletionHandler { (dataTasks, uploadTasks, downloadTasks) in
switch request {
case .DataTask:
dataTasks.forEach { $0.cancel() }
print("- - - Data task was canceled!")
case .UploadTask:
uploadTasks.forEach { $0.cancel() }
print("- - - Upload task was canceled!")
case .DownloadTask:
downloadTasks.forEach { $0.cancel() }
print("- - - Download task was canceled!")
case .ZeroTask:
print("- - - Zero tasks was found!")
}
}
}
Where "CancelRequestType" is enum. So you can call the method like API.cancel(request: .UploadTask)
enum CancelRequestType: String {
case DownloadTask = "DownloadTask"
case DataTask = "DataTask"
case UploadTask = "UploadTask"
case ZeroTask = "Zero"
}
来源:https://stackoverflow.com/questions/34888793/how-to-cancel-alamofire-upload