Swift 为backgroundSession.uploadTask实现完成处理程序
我已经(几乎)成功地实现了Swift 为backgroundSession.uploadTask实现完成处理程序,swift,nsurlsessiondatatask,nsurlsessionuploadtask,Swift,Nsurlsessiondatatask,Nsurlsessionuploadtask,我已经(几乎)成功地实现了URLSessionDelegate、URLSessionTaskDelegate和URLSessionDataDelegate,这样我就可以在后台上传我的对象了。但我不确定如何实现完成处理程序,以便在服务器返回statuscode=200 我现在像这样开始uploadTask let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.myObject\(myO
URLSessionDelegate
、URLSessionTaskDelegate
和URLSessionDataDelegate
,这样我就可以在后台上传我的对象了。但我不确定如何实现完成处理程序,以便在服务器返回statuscode=200
我现在像这样开始uploadTask
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.myObject\(myObject.id)")
let backgroundSession = URLSession(configuration: configuration,
delegate: CustomDelegate.sharedInstance,
delegateQueue: nil)
let url: NSURL = NSURL(string: "https://www.myurl.com")!
let urlRequest = NSMutableURLRequest(url: url as URL)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let uploadTask = backgroundSession.uploadTask(with: urlRequest as URLRequest, fromFile: path)
uploadTask.resume()
我试图在uploadTask
的初始化中添加一个闭包,但是xcode显示了一个错误,这是不可能的
我有我的自定义类CustomDelegate:
class CustomDelegate : NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
static var sharedInstance = CustomDelegate()
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("\(session.configuration.identifier!) received data: \(data)")
do {
let parsedData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let status = parsedData["status"] as! NSDictionary
let statusCode = status["httpCode"] as! Int
switch statusCode {
case 200:
// Do something
case 400:
// Do something
case 401:
// Do something
case 403:
// Do something
default:
// Do something
}
}
catch {
print("Error parsing response")
}
}
}
它还为代理实现其他功能
我想知道的是,上传已经完成,这样我就可以从
CustomDelegate
中更新我觉得很难(可能不可能?)的UI和数据库。如果您只对检测请求的完成感兴趣,最简单的方法是使用闭包:
class CustomDelegate : NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
static var sharedInstance = CustomDelegate()
var uploadDidFinish: ((URLSessionTask, Error?) -> Void)?
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
DispatchQueue.main.async {
uploadDidFinish?(task, error)
}
}
}
然后,视图控制器将在启动请求之前设置此关闭,例如
CustomDelegate.sharedInstance.uploadDidFinish = { [weak self] task, error in
// update the UI for the completion here
}
// start the request here
如果您想针对多种情况(例如,不仅在上传完成时更新UI,而且在上传发送时更新UI),理论上可以设置多个闭包(一个用于完成,一个用于进度),但通常您会采用自己的委托协议模式。(就个人而言,我会将
CustomDelegate
重命名为类似于UploadManager
的名称,以避免混淆谁是什么的委托人,但这取决于您。)
例如,您可以执行以下操作:
protocol UploadDelegate: class {
func didComplete(session: URLSession, task: URLSessionTask, error: Error?)
func didSendBodyData(session: URLSession, task: URLSessionTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)
}
然后,在网络请求管理器(您的CustomDelegate
实现)中,定义delegate
属性:
weak var delegate: UploadDelegate?
在适当的URLSession
delegate方法中,可以调用自定义委托方法将信息传递给视图控制器:
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
// do whatever you want here
DispatchQueue.main.async {
delegate?.didComplete(session: session, task: task, didCompleteWithError: error)
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
// do whatever you want here
DispatchQueue.main.async {
delegate?.didSendBodyData(session: session, task: task, bytesSent: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend)
}
}
然后,您将声明视图控制器符合新协议,并实现以下方法:
class ViewController: UIViewController, UploadDelegate {
...
func startRequests() {
CustomDelegate.sharedInstance.delegate = self
// initiate request(s)
}
func didComplete(session: URLSession, task: URLSessionTask, error: Error?) {
// update UI here
}
func didSendBodyData(session: URLSession, task: URLSessionTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
// update UI here
}
}
现在,您可以更新这个UploadDelegate
协议来捕获模型信息,并将其作为参数传递给您的方法,但希望这能说明基本思想
一些小的观察:
NSURL
和NSMutableURLRequest
类型,例如:
let url = URL(string: "https://www.myurl.com")!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let uploadTask = backgroundSession.uploadTask(with: urlRequest, fromFile: path)
uploadTask.resume()
direceivedata
中查找statusCode
。您真的应该在didReceiveResponse
中这样做。另外,您通常从urresponse
获取状态代码didReceiveData
中的响应。通常,您应该在didcompletewitheror
中执行此操作(以防需要多次调用didcreceivedata
才能接收整个响应)myObject.id
是什么,但是您选择的标识符,“com.example.myObject\(myObject.id)”
有点可疑:
- 是否为每个对象创建新的
实例?对于所有请求,您可能都需要一个URLSession
- 当您的应用程序在后台继续上载时被挂起/丢弃,当应用程序重新启动时,您是否有可靠的方法重新启动相同的会话对象
handleEventsForBackgroundURLSession
)实施。如果您希望进行进度更新,可以使用.Unrelated,但不必实例化
NSURL
和NSMutableURLRequest
并强制转换为URL
和URLRequest
,您应该首先创建URL
和URLRequest
。唯一的诀窍是,既然您想变异URLRequest
,就使用var
,而不是let
@Rob,我已经这样做了,但我的问题是如何“退出”CustomDelegate
类。例如,如果我在mainViewController
中,我调用了一个函数来设置uploadTask
,那么我想更新用户界面。例如,您给自定义委托类一些机制来通知主视图控制器。典型的方法是“完成处理程序”闭包或协议委托模式(即:1.让您的自定义委托对象定义一个协议,通过该协议它将通知更新;2.拥有自己的该类型的委托
属性;3.让主视图控制器符合该协议;4.启动请求时,将视图控制器设置为“自定义委托对象”的委托)。或发布通知。感谢@Rob的回答。是否可以在后台上传任务中使用完成处理程序关闭?谢谢,回答得很好!除了获取状态代码之外,我已经让它工作了。我认为我实现的didReceiverResponse
不正确,因为无论发生什么情况,它都不会被调用。知道吗这是为什么?干杯。我会仔细检查方法签名并确保其正确性:。否则,我建议发布一个新问题,并添加一个。@Rob我正在尝试为具有后台会话的下载任务实现一个委托,但我的任务没有完成