【问题标题】:NSURLSession delegates not calledNSURLSession 委托未调用
【发布时间】: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 参数

标签: ios swift


【解决方案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 - 它基于NSURLConnectionNSURLSession 旨在取代。在任何情况下,持久化会话对象都不能解决问题。
  • 它只是一个有趣的 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")
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多