swift:URLSessionConfiguration

时间:2017-08-20 18:20:30

标签: ios swift nsurlsession

我有FirstViewController按钮可以移动到SecondTableViewController。在SecondTableViewController我有单元格,如果我点击单元格下载开始。

问题:如果我从SecondTableViewController开始FirstViewController开始下载并在FirstViewController中返回,并且在SecondTableViewController中移动后,我会收到此信息:

A background URLSession with identifier com.example.DownloadTaskExample.background already exists!

我无法下载我的文件。怎么解决?

SecondTableViewController中的代码:

var backgroundSession: URLSession!
var index = 0

override func viewDidLoad() {
    super.viewDidLoad()
    let sessionConfig = URLSessionConfiguration.background(withIdentifier: "com.example.DownloadTaskExample.background")
        backgroundSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue())
}

下载文件的代码:

let url = URL(string: "link")!
let downloadTaskLocal = ViewController.backgroundSession.downloadTask(with: url)
downloadTaskLocal.resume()

新代码:

class Networking {
    static let shared = Networking()
    var backgroundSession = URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "com.example.DownloadTaskExample.background"), delegate: URLSession() as? URLSessionDelegate, delegateQueue: OperationQueue())
}

class ViewController: UITableViewController, URLSessionDownloadDelegate {

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let url = URL(string: "link")!
        let downloadTaskLocal = Networking.shared.backgroundSession.downloadTask(with: url)
        downloadTaskLocal.resume()
    }
}

UPD

class BackgroundSession: NSObject {

    static let shared = BackgroundSession()

    static let identifier = "com.example.DownloadTaskExample.background"

    var session: URLSession!

    private override init() {
        super.init()

        let configuration = URLSessionConfiguration.background(withIdentifier: BackgroundSession.identifier)
        session = URLSession(configuration: configuration, delegate: self as? URLSessionDelegate, delegateQueue: OperationQueue())
    }


}

class ViewController: UITableViewController, URLSessionDownloadDelegate{

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let url = URL(string: "http:link\(indexPath.row + 1)")!
        let downloadTaskLocal = BackgroundSession.shared.session.downloadTask(with: url)
        downloadTaskLocal.resume()
}
}

2 个答案:

答案 0 :(得分:1)

如果你真的在使用后台会话,你应该确保只实例化一次。您需要使这个单TCheckBox个实例不仅可用于第二个视图控制器的多个实例,而且您还需要让您的应用程序委托能够引用它(例如handleEventsForBackgroundURLSession必须保存完成处理程序,被调用但会话委托的urlSessionDidFinishEvents(forBackgroundURLSession:))。

一种方法是让app委托实例化它,然后传递它。更简单的是,您可以使用单例模式(如https://stackoverflow.com/a/44140059/1271826所示)。

诀窍是,在将此后台会话与第二个视图控制器的任何特定实例分离时,您希望如何从后台会话通知第二个视图控制器事件。您可能想要使用NotificationCenter。或者,您可以为后台会话提供第二个视图控制器可以设置的一些闭包属性(并为每个新实例重置)。如果不知道第二个视图控制器正在做什么,很难准确说出来。

但关键是要确保在应用程序的生命周期内只有一个后台会话实例。

答案 1 :(得分:0)

首先,您应该将所有与网络相关的代码移到一个单独的类中,并且不应该将它放在ViewController类中。 backgroundSession也不应该是隐式解包的选项。

与此同时,您可以使用以下方法修改当前代码(将backgroundSession的声明移至类级别):

var backgroundSession = URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "com.example.DownloadTaskExample.background"), delegate: self, delegateQueue: OperationQueue())

var index = 0

override func viewDidLoad() {
    super.viewDidLoad()
    SecondTableViewController.backgroundSession //do something with the session, it will only be evaluated when you are trying to access it
}

从长远来看,您应该为网络相关代码创建一个类,它应该有一个单例实例。

class Networking {
    static let shared = Networking()
    var backgroundSession = URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "com.example.DownloadTaskExample.background"), delegate: self, delegateQueue: OperationQueue())
}

这样您就可以访问Networking类的单例实例 撰写Networking.shared并通过backgroundSession访问Networking.shared.backgroundSession