NSURLSessionTaskDelegate 方法 URLSession:task:didCompleteWithError: 从不调用
Posted
技术标签:
【中文标题】NSURLSessionTaskDelegate 方法 URLSession:task:didCompleteWithError: 从不调用【英文标题】:NSURLSessionTaskDelegate method URLSession:task:didCompleteWithError: never called 【发布时间】:2014-11-17 23:58:33 【问题描述】:我所有的网络代码都依赖于 NSURLSession 委托方法——而不是完成处理程序。我的数据和下载任务都很好,但我的上传任务从来没有导致
URLSession:task:didCompleteWithError:
被调用。然而
URLSession:dataTask:didReceiveData:
和 URLSession:dataTask:willCacheResponse:completionHandler:
委托方法 ARE 被调用。
如果我在会话对象上将资源超时设置为非常低的值,那么didCompleteWithErrors
会被调用,但这显然不是解决方案。
有什么想法吗?我快要疯了。
谢谢。
【问题讨论】:
嗨@mph 你是如何设置这个任务委托的?实际上我遇到了一些问题,这些代表没有被调用。 【参考方案1】:如果您实现willCacheResponse
,您将不会看到调用didCompleteWithError
,但如果实现未能实际调用completionHandler
。您必须拨打completionHandler
。
所有提供completionHandler
参数的各种NSURLSession
委托方法(例如身份验证质询、重定向等)也是如此。如果你实现了这些各自的方法,你必须确保completionHandler
被调用。
【讨论】:
谢谢。我知道它一定是像这样微不足道的事情。 发布我的问题后,我注意到我的一些数据和下载任务也遇到了同样的问题。我猜简短而甜蜜的单元测试并不总是遇到同样的问题,这实际上使它成为一个更令人讨厌和(看似)无证的问题。啊。 在为 Apple 的文档辩护时,它说,“如果你的委托实现了这个方法,它必须调用这个完成处理程序”(强调来自原始文档)。它并不能准确地说明如果你不调用completionHandler
会发生什么(更糟糕的是,文档描述了会导致泄漏,但忽略了承认可能出现的更广泛的问题),但在他们的辩护中,他们是公平的明确必须调用完成处理程序。但我能感受到你的痛苦:我知道这个问题的唯一原因是我自己曾经经历过。【参考方案2】:
Rob 的回答是正确的,给了我一个很大的线索。但是 - 对于我的具体问题 - 为什么可能不会调用 NSURLSessionTaskDelegate
方法并没有引起我的注意。如果可以允许我提供另一个重点不同的答案。
许多NSURLSession
任务创建方法有两种变体;一个带有completionHandler
参数,一个没有。
例如:
func dataTaskWithRequest(_ request: NSURLRequest) -> NSURLSessionDataTask
func dataTaskWithRequest(_ request: NSURLRequest, completionHandler completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask
如果使用completionHandler
方法,那么任何委托方法——在这种情况下为NSURLSessionTaskDelegate
将被忽略。尽管在 NSURLSession
初始化程序中指定了委托。
以下 Playground 代码演示了这一点。切换 task
声明 cmets 以查看是否调用了委托:
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
class MyDelegate:NSObject, NSURLSessionTaskDelegate
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
NSLog("Delegate called")
let myDel = MyDelegate()
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: myDel, delegateQueue: NSOperationQueue())
let url = NSURL(string: "http://httpbin.org")
let request: NSURLRequest = NSURLRequest(URL: url!)
// With completionHandler, delegate method above NOT called
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: (data, response, error) in
NSLog("Task done")
)
// Without completionHandler, delegate method above IS called
//let task : NSURLSessionDataTask = session.dataTaskWithRequest(request)
task.resume()
TLDR: 想知道为什么不调用NSURLSession
的委托方法?使用替代方法签名来创建您的会话任务; 省略了completionHandler 参数。
【讨论】:
完成处理程序块没有对委托方法中使用的(NSURLSessionTask *)task
参数的引用。如果没有委托的task
,如何在块内重试任务?
这个答案是正确的,顺便说一句...`uploadTaskWithRequest:fromData:
命中了委托方法,但uploadTaskWithRequest:fromData:completionHandler:
没有。
就我而言,即使我没有使用 completionHandler 方法,也不会调用委托回调。【参考方案3】:
在这种情况下有人可能想要检查的另一种可能性是,您的 URLSession 委托方法未标记为私有。如果是,则不会调用方法...如果您将修饰符留在方法之外,这很容易意外发生,然后在警告上使用自动修复来修复方法的修饰符(使其私有)。
方法签名应该是:
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
【讨论】:
或“open func”——今天这让我有点吃惊,感谢“正确”的答案,尽管其他问题也是完全有效的问题。放弃委托模式! @snakeoil 关于开放是有效的重要一点,只是可以看到的东西!很高兴它可以提供帮助,因为这让我困惑了一段时间。 WTF!就是这样。编译器没有警告我他们需要公开。但奇怪的是,一些委托函数被调用了。【参考方案4】:为了在此处扩展另一个答案,NSURLSession docs 声明将调用完成处理程序或委托方法。
与大多数网络 API 一样,NSURLSession API 是高度异步的。它以两种方式中的一种将数据返回到您的应用,具体取决于您调用的方法:
传输成功完成或出现错误时调用的完成处理程序块。
在接收到数据和传输完成时调用会话委托上的方法。
这里有一个更具体的问题:
NSURLSession delegate and completionHandler
【讨论】:
【参考方案5】:我解决了这个问题,如果有的话,在 willCacheResponse
函数中添加 completionHandler
。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *__nullable cachedResponse))completionHandler
NSLog(@"%s", __FUNCTION__);
completionHandler(proposedResponse);
【讨论】:
以上是关于NSURLSessionTaskDelegate 方法 URLSession:task:didCompleteWithError: 从不调用的主要内容,如果未能解决你的问题,请参考以下文章
Swift 中这些 NSURLSession 方法的代表是啥?