Si vous êtes uniquement intéressé à détecter l'achèvement de la demande, l'approche la plus simple est d'utiliser une fermeture:
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)
}
}
}
Ensuite, votre contrôleur de vue fixerait cette fermeture avant de lancer la demande, par exemple
CustomDelegate.sharedInstance.uploadDidFinish = { [weak self] task, error in
// update the UI for the completion here
}
// start the request here
Si vous souhaitez mettre à jour votre interface utilisateur pour de multiples situations (par exemple, non seulement comme ajouts fini, mais les progrès que les téléchargements sont envoyés), vous pourriez théoriquement définir plusieurs fermetures (un pour l'achèvement, un pour progrès), mais vous adopteriez souvent votre propre modèle de protocole délégué. (Personnellement, je renomme CustomDelegate
à quelque chose comme UploadManager
pour éviter toute confusion au sujet de qui est un délégué à quoi, mais c'est à vous.)
Par exemple, vous pourriez faire:
protocol UploadDelegate: class {
func didComplete(session: URLSession, task: URLSessionTask, error: Error?)
func didSendBodyData(session: URLSession, task: URLSessionTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)
}
Ensuite, dans votre gestionnaire de requêtes réseau (votre CustomDelegate
de mise en œuvre), définir une propriété delegate
:
weak var delegate: UploadDelegate?
Dans les méthodes déléguées URLSession
appropriées, vous appelez votre délégué sur mesure meth ods de transmettre les informations au contrôleur de vue:
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)
}
}
Ensuite, vous souhaitez déclarer votre contrôleur de vue pour se conformer à votre nouveau protocole et mettre en œuvre ces méthodes:
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
}
}
Maintenant, vous pouvez mettre à jour ce protocole UploadDelegate
pour capturer des informations de modèle et passer cela en tant que paramètre à vos méthodes, aussi, mais j'espère que cela illustre l'idée de base.
Quelques observations mineures:
Lors de la création de votre session, vous devriez probablement exciser les NSURL
et NSMutableURLRequest
types de votre code, par exemple:
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()
Vous recherchez statusCode
dans didReceiveData
. Vous devriez vraiment le faire en didReceiveResponse
. En outre, vous obtenez généralement le code d'état à partir du . Vous analysez la réponse dans didReceiveData
. Généralement, vous devriez le faire dans didCompleteWithError
(juste au cas où il faut plusieurs appels à didReceiveData
pour recevoir la réponse entière).
Je ne sais pas ce que myObject.id
est, mais l'identifiant que vous avez choisi, "com.example.myObject\(myObject.id)"
, est un peu suspect:
Êtes-vous créez une nouvelle instance URLSession
pour chaque objet? Vous en voulez probablement un pour toutes les demandes. Lorsque votre application est suspendue/abandonnée pendant le téléchargement en arrière-plan, lorsque l'application est redémarrée, disposez-vous d'un moyen fiable de réactiver les mêmes objets de session?
En général, vous voudriez une seule session de téléchargement pour tous vos téléchargements, et le nom doit être cohérent. Je ne dis pas que ne peut pas le faire comme vous l'avez fait, mais il semble que cela va être problématique de recréer ces sessions sans faire de travail supplémentaire. C'est à vous. Tout cela pour dire que je m'assurerais de tester votre processus de téléchargement en arrière-plan si l'application est terminée et redémarrée en arrière-plan une fois les téléchargements terminés. Cela semble être incomplet/fragile, mais j'espère que je vais juste sauter à des conclusions incorrectes et que vous avez tout cela fonctionne et que vous n'avez simplement pas partagé quelques détails (p. Ex. handleEventsForBackgroundURLSession
de votre délégué) pour des raisons de concision. est très apprécié).
Mettre en œuvre [ 'didCompleteWithError'] (https://developer.apple.com/reference/foundation/urlsessiontaskdelegate/1411610-urlsession). Et si vous voulez que les mises à jour progressent au fur et à mesure, vous pouvez utiliser ['didSendBodyData'] (https://developer.apple.com/reference/foundation/urlsessiontaskdelegate/1408299-urlsession). – Rob
Non reliée, mais plutôt que d'instancier 'NSURL' et' NSMutableURLRequest' et de convertir 'URL' et' URLRequest', vous devez simplement créer 'URL' et' URLRequest' en premier lieu. Le seul truc est que puisque vous voulez muter le 'URLRequest', utilisez' var', pas 'let'. – Rob
@Rob Je l'ai fait mais mon problème est comment "sortir de" la classe "CustomDelegate". Si je suis par exemple dans 'mainViewController' et que j'appelle une fonction qui fait la configuration de' uploadTask' alors je veux mettre à jour l'interface utilisateur par exemple – Frederik