我有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()
}
}
答案 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
。