NSURLSessionTaskDelegate方法URLSession:task:didCompleteWithError:从不调用

时间:2014-11-17 23:58:34

标签: ios objective-c nsurlsession

我的所有网络代码都依赖于NSURLSession委托方法 - 而不是完成处理程序。我的数据&下载任务一切都很好,但我的上传任务永远不会导致 URLSession:task:didCompleteWithError:被召唤。然而 调用了URLSession:dataTask:didReceiveData:URLSession:dataTask:willCacheResponse:completionHandler:委托方法 ARE

如果我在会话对象上将资源超时设置为非常低的值,则会调用didCompleteWithErrors,但这显然不是解决方案。

有什么想法吗?我快要疯了。

感谢。

5 个答案:

答案 0 :(得分:5)

如果您实施didCompleteWithError,则不会看到willCacheResponse,但如果实施无法实际调用completionHandler。您必须致电completionHandler

任何和所有提供NSURLSession参数的completionHandler委托方法(例如身份验证质询,重定向等)也是如此。如果实现这些相应的方法,则必须确保调用completionHandler

答案 1 :(得分:2)

罗布的答案是对的,给了我一个很大的线索。但是 - 对于我的具体问题 - 它并没有向我跳出为什么不能调用NSURLSessionTaskDelegate方法。如果我可以被允许以不同的焦点提供另一个答案。

许多NSURLSession任务创建方法有两种变体;一个completionHandler参数,一个没有。

例如:

func dataTaskWithRequest(_ request: NSURLRequest) -> NSURLSessionDataTask

func dataTaskWithRequest(_ request: NSURLRequest, completionHandler completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask

如果使用completionHandler方法,则会忽略任何委托方法(在本例中为NSURLSessionTaskDelegate 。尽管已在NSURLSession初始化程序中指定了委托,但仍然存在这种情况。

以下Playground代码演示了这一点。切换task声明注释以查看是否调用了委托:

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参数的内容

答案 2 :(得分:1)

在这种情况下,有人可能想要检查的另一种可能性是您的URLSession委托方法未标记为私有。如果是的话,这些方法将不会被调用...如果将修饰符置于方法之外,然后在警告上使用自动修复方法来固定方法的修饰符(将其设为私有),这很容易偶然发生。

方法签名应为:

public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 

答案 3 :(得分:0)

To expand upon another answer here, the NSURLSession docs state that either the completion handler or delegate methods will be called.

Like most networking APIs, the NSURLSession API is highly asynchronous. It returns data to your app in one of two ways, depending on the methods you call:

  • To a completion handler block that is called when a transfer finishes successfully or with an error.

  • By calling methods on the session’s delegate as data is received and when the transfer is complete.

A more specific ask of this question is here:

NSURLSession delegate and completionHandler

答案 4 :(得分:0)

如果您有completionHandler功能,我就像在willCacheResponse函数中添加- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *__nullable cachedResponse))completionHandler { NSLog(@"%s", __FUNCTION__); completionHandler(proposedResponse); } 一样解决了这个问题。

{{1}}