NSURLSession 委托未调用
Posted
技术标签:
【中文标题】NSURLSession 委托未调用【英文标题】:NSURLSession delegates not called 【发布时间】:2014-11-02 00:10:49 【问题描述】:在下面的代码中,文件下载得很好。但是,似乎没有调用任何委托方法,因为我没有收到任何输出。 progressView 也没有更新。知道为什么吗?
import Foundation
import UIKit
class Podcast: PFQueryTableViewController, UINavigationControllerDelegate, MWFeedParserDelegate, UITableViewDataSource, NSURLSessionDelegate, NSURLSessionDownloadDelegate
func downloadEpisodeWithFeedItem(episodeURL: NSURL)
var request: NSURLRequest = NSURLRequest(URL: episodeURL)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
var downloadTask = session.downloadTaskWithURL(episodeURL, completionHandler: (url, response, error) -> Void in
println("task completed")
if (error != nil)
println(error.localizedDescription)
else
println("no error")
println(response)
)
downloadTask.resume()
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64)
println("didResumeAtOffset")
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
println(Float(downloadProgress))
println("sup")
epCell.progressView.progress = Float(downloadProgress)
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL)
println(location)
【问题讨论】:
尝试将 [NSOperationQueue mainQueue] 而不是 nil 传递给 delegateQueue 参数 【参考方案1】:根据我的测试,您必须选择是要使用委托还是完成处理程序 - 如果您同时指定两者,则只会调用完成处理程序。这段代码给了我运行进度更新和didFinishDownloadingToURL
事件:
func downloadEpisodeWithFeedItem(episodeURL: NSURL)
let request: NSURLRequest = NSURLRequest(URL: episodeURL)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let downloadTask = session.downloadTaskWithURL(episodeURL)
downloadTask.resume()
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64)
println("didResumeAtOffset: \(fileOffset)")
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
println("downloadProgress: \(downloadProgress)")
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL)
println("didFinishDownloadingToURL: \(location)")
println(downloadTask)
来自NSURLSession
documentation,以下是相关部分:
与大多数网络 API 一样,NSURLSession API 是高度异步的。它以两种方式之一返回数据,具体取决于您调用的方法:
到完成处理程序块,当传输成功完成或出现错误时将数据返回到您的应用程序。 在收到数据时调用自定义委托上的方法。 下载到文件完成后调用自定义委托上的方法。
因此,根据设计,它会将数据返回给完成处理程序块或委托。但正如这里所证明的,不是两者兼而有之。
【讨论】:
我不确定这是否正确,否则那将是可怕的 API 设计。此外看看 AFNetworking,AFURLSessionManager 的所有设计都基于委托回调,但您仍然可以使用完成处理程序创建请求... 这可能是可怕的 API 设计,也可能是一个错误,因为该行为未记录在案。 AFNetworking 早于NSURLSession
- 它基于NSURLConnection
,NSURLSession
旨在取代。在任何情况下,持久化会话对象都不能解决问题。
它只是一个有趣的 API 细节,处理程序覆盖了委托:)
“有趣”是一种表达方式!为这个困惑太久了。为什么我不能使用完成处理程序,例如,同时通过委托管理缓存行为?看起来很奇怪。
我可以确认 completionHandler 确实抑制了代表。另外,不要忘记实现URLSession:task:didCompleteWithError:
,这样您也会收到任何错误! (完成处理程序为您提供NSError *error
参数)。【参考方案2】:
有趣的是,Apple specifically explains this behavior in their NSURLSessionDataDelegate
(但既不在基础委托 NSURLSessionTaskDelegate
也不在 NSURLSessionDownloadDelegate
中)
注意
NSURLSession 对象不需要有委托。如果没有分配委托,当您在该会话中创建任务时,您必须提供完成处理程序块来获取数据。
完成处理程序块主要用作使用自定义委托的替代方案。 如果您使用采用完成处理程序块的方法创建任务,则不会调用用于响应和数据传递的委托方法。
【讨论】:
但是即使提供了完成块,也会调用上传任务委托!【参考方案3】:斯威夫特 3
class ViewController: UIViewController
var urlLink: URL!
var defaultSession: URLSession!
var downloadTask: URLSessionDownloadTask!
// MARK: Button Pressed
@IBAction func btnDownloadPressed(_ sender: UIButton)
let urlLink1 = URL.init(string: "https://github.com/VivekVithlani/QRCodeReader/archive/master.zip")
startDownloading(url: urlLink!)
@IBAction func btnResumePressed(_ sender: UIButton)
downloadTask.resume()
@IBAction func btnStopPressed(_ sender: UIButton)
downloadTask.cancel()
@IBAction func btnPausePressed(_ sender: UIButton)
downloadTask.suspend()
func startDownloading (url:URL)
let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
downloadProgress.setProgress(0.0, animated: false)
downloadTask = defaultSession.downloadTask(with: urlLink)
downloadTask.resume()
// MARK:- URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
print("File download succesfully")
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
downloadProgress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
downloadTask = nil
downloadProgress.setProgress(0.0, animated: true)
if (error != nil)
print("didCompleteWithError \(error?.localizedDescription)")
else
print("The task finished successfully")
【讨论】:
以上是关于NSURLSession 委托未调用的主要内容,如果未能解决你的问题,请参考以下文章
应该如何处理 NSURLAuthenticationMethodXMobileMeAuthToken?
URLSessionDidFinishEventsForBackgroundURLSession 未调用-Objective-C