Swift 3和NSURLSession问题

8
感谢Apple,让我的iOS 9项目“Swift 2.3”在iOS 10的“Swift 3”中完全无法使用...
我几乎修复了所有问题,除了我在使用NSURLSession时遇到的问题。Xcode告诉我它已被重命名为URLSession,如果我重命名它,Xcode会告诉我:
“未声明类型URLSession的用法”。
Foundation已被导入。
问题是什么?
例如,我是这样使用它的...
lazy var defaultSession: URLSession = {
    let configuration = URLSessionConfiguration.background(withIdentifier: "reCoded.BGDownload")
    configuration.sessionSendsLaunchEvents = true
    configuration.isDiscretionary = true
    let session = URLSession(configuration: configuration, delegate: self, delegateQueue, queue: nil)
    return session
}()

即使使用委托方法,仍然存在相同的问题。

@EricD 我已经更新了描述,如果您能看到,请查看。 - Raffi
1
你的代码中的URLSession没有问题。我知道这听起来很荒谬,但是...你确定你在使用Xcode 8吗? :) 如果是的话,可能有一个冲突的声明在某个地方... - Eric Aya
@EricD 是的我确定!我会再检查一遍看看会发生什么。如果我找到了什么,我会更新的。谢谢伙计。 - Raffi
2
我遇到了同样的问题。没有理由被踩。 - Siamaster
5个回答

7

尝试在使用URLSession的地方,改用Foundation.URLSession


3
请问您能否解释一下为什么? - Ahmad F

2

/搞定了/ 在某些情况下,尝试将代码复制到其他地方,然后删除所有使用URLSession的类中的内容,然后重新输入会话方法,再将复制的代码放回去,这样应该就可以了。


这种方法对我有效。它似乎以某种方式消除了编译器的混乱 @Droppy - Raffi
你能否分享一下你的完整最终解决方案?我正在努力让我的后台URLSession可靠地运行。文档很混乱,而且很多内容都是旧的,不适用于Swift 3。 - Wayne Henderson
展示一下你遇到问题的代码,我会尽力帮助你。 - Raffi
谢谢你的提供。看起来我的后台会话和任务现在实际上正在工作。我认为我的问题可能是在使用UserDefaults时运行后台URL会话。一旦我解决了这个问题,我可能会回来。 - Wayne Henderson
请查看我的完整回复。 - Wayne Henderson
@WayneHenderson 没问题 :) - Raffi

1

更新您的URLSession函数如下:

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    self.data.append(data as Data)  
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    if error != nil {
        print("Failed to download data")
    }else {
        print("Data downloaded")
        self.parseJSON()
    }
}

0

我可以解释如何做,但是通过玩弄代码,我在两天的挫折后让它在SWIFT 3中工作了。我猜SWIFT 3删除了很多不必要的单词。

let task = Foundation.URLSession.shared.dataTask(with: <#T##URL#>, completionHandler: <#T##(Data?, URLResponse?, Error?) -> Void#>)

0

这是我目前的进展。虽然不完美,但也能用一半的时间。

首先,在定义我的URLsession的类中:

import Foundation
class Central: NSObject, URLSessionDataDelegate, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDownloadDelegate {

我不认为所有这些都是必要的,但它就在那里。然后这里是由我的后台获取调用的函数:

func getWebData() {
    var defaults: UserDefaults = UserDefaults.standard
    let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: "myBGconfig")
    let backgroundSession = URLSession(configuration: backgroundConfigObject, delegate: self, delegateQueue: nil)
    urlString = "https://www.powersmartpricing.org/psp/servlet?type=dayslider"
    if let url = URL(string: urlString) {
    let rateTask = backgroundSession.downloadTask(with: URL(string: urlString)!)
    rateTask.taskDescription = "rate"
    rateTask.resume()
}

当任务返回时:

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL ) {
    if downloadTask.taskDescription == "rate" {  // I run 2 web tasks during the session
        if let data = NSData(contentsOf: location) {
           var return1 = String(data: data as! Data, encoding: String.Encoding.utf8)!
             DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: .now() + 0.2){
                var defaults: UserDefaults = UserDefaults.standard
                defaults.set(myNumber, forKey: "electricRate") // myNumber is an extract of the text in returned web data
                defaults.set(Date(), forKey: "rateUpdate")
                defaults.synchronize()
                self.calcSetting()  //Calls another function defined in the same class.  That function sends the user a notification.
                let notificationName = Notification.Name("GotWebData")
                NotificationCenter.default.post(name: notificationName, object: nil)
            }   //  Closes the Dispatch
        }
      if session.configuration.identifier == "myBGconfig" {
          print("about to invalidate the session")
          session.invalidateAndCancel()
       }
}

我还没有想出如何在两个任务都完成后终止会话,所以现在当任一个任务完成时,我就使用上面的invalidateAndCancel来终止会话。

最后,捕获错误:

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didCompleteWithError: Error?) {
      if downloadTask.taskDescription == "rate" {
        print("rate download failed with error \(didCompleteWithError)")
    }
    if downloadTask.taskDescription == "other" {
        print("other download failed with error \(didCompleteWithError)")
    }
 downloadTask.resume()  //  I'm hoping this retries if a task fails?
}

func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
    if let error = error as? NSError {
        print("invalidate, error %@ / %d", error.domain, error.code)
    } else {
        print("invalidate, no error")
    }
}

我能理解为什么你的任务有时候不能立即执行,当你创建一个后台会话时,请将其isDiscretionary属性设置为false,这样你的任务就会立即执行。在这里阅读isDiscretionary referance,关于取消会话请参考这里的答案Cancelling NSURLSession - Raffi
该引用说isDiscretionary的默认值为false。我将尝试进行设置,但这应该无关紧要吧?至于取消会话,我已经接近成功了。我正在使用一个标志,但存在时间问题,因为我的标志是在调度期间设置的。在任务标志设置为“完成”之前,即决定使其无效太快了。我正在处理这个问题。 - Wayne Henderson
试一下,告诉我发生了什么。出于某种原因,这种方式对我有效。 - Raffi
到目前为止,我已经完成了两个后台获取。一个起作用,另一个不起作用。哦,又有一个成功完成,所以一共完成了3个中的2个。每当调用后台获取时,我都会向屏幕发送通知。然后,我的两个任务中的每一个在完成时发送通知。因此,如果只收到获取通知而没有两个任务通知也到达,则表示失败。如果所有3个通知都到达,则表示成功。我的任务标志现在正常工作,当两个任务完成时,我可以使会话失效。 - Wayne Henderson
已经运行了几个小时,似乎有80%的时间在工作。虽然不是100%让人沮丧,但比以前好多了。我相信将isDiscretionary设置为false确实有所帮助。但愿有更好的方法来调试后台正在发生的事情。 - Wayne Henderson
如果您在后台启动后台会话,则无论您将isDiscretionary设置为什么值,它始终为true。如果是这种情况,那么您不必担心,系统会处理它。 - Raffi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接