I am trying to upload a file to the server and after the completion of upload, I'm supposed to get a JSON response.
I can see the data when I use the completion block
uploaderSession.dataTask(with: request, completionHandler: { (data, response, error) in
print("\(NSString(data: data!, encoding: 4))")
}).resume()
I need the same data but using the custom delegates
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
session.dataTask(with: request).resume()
I implemented
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
but didReceiveData is not called.
Please suggest what can be done to get the JSON data at the end of completion of file upload
Thanks in advance
ok so got the answer just posting cause it can help somebody
we have to call
completionHandler(URLSession.ResponseDisposition.allow)
in
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void)
Related
I want to get my UIWebView's current location when browsing an SPA (single-page-application) website.
(Yes, I am intentionally working with UIWebView instead of WKWebView.)
I know that there are multiple approaches to getting the current URL, such as:
webView.request?.url?.absoluteString
webView.request?.mainDocumentURL?.absoluteString
webView.stringByEvaluatingJavaScript(from: "window.location")
However, for an SPA website, for each of the approaches above, I am getting the initial url, even when I navigate to another page on that SPA website.
What can I do?
Step 1: Creating a custom URLProtocol to catch data requests
class CustomURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {
// If this returns false, the first request will basically stops at where it begins.
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
print(self.request.url) // URL of Data requests made by UIWebView before loading.
URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil).dataTask(with: self.request).resume()
}
override func stopLoading() {
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
// Data request responses received.
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
completionHandler(.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
// Data request data received.
self.client?.urlProtocol(self, didLoad: data)
self.urlSession(session, task: dataTask, didCompleteWithError: nil)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
self.client?.urlProtocol(self, didFailWithError: error)
return
}
print(self.request.url) // URL of Data requests completed.
self.client?.urlProtocolDidFinishLoading(self)
}
}
Step 2: Registering your custom URLProtocol
Register your custom URLProtocol before loading your SPA in UIWebview.
URLProtocol.registerClass(CustomURLProtocol.self)
Hope this helps! Sorry for the delay, was caught up at work.
Using either NSURLConnection or NSURLSession, how can I tell when data has started to arrive? My download may be large or my connection slow so I want to make an update to the UI once data starts to arrive.
NSUrlSession has a delegate that should help you, if you're interested in knowing the each block of data is received.
func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive data: Data)
And this delegate if just the headers received is useful.
optional func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive response: URLResponse,
completionHandler: #escaping (URLSession.ResponseDisposition) -> Void)
I want to download a file from a certain url .
what I need is the data delegate ( the delegate which gives me the downloaded data) .
I implemented the :
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
delegate but it doesn't get called .
my code is :
func download(url: URL)
{
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("apending ")
self.dataaa.append(data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
print("here")
}
the two delegate functions don't get called !
You're using the delegate methods for a data task, but you're creating a download task. Those two task types work differently and use completely different delegate methods.
I would like to process data as it comes in, so I've instiated a URL session like so:
let session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: operationQueue);
I also set the class to be a URLSessionDataDelegate:
class ViewController: UITableViewController, URLSessionDataDelegate{
Lastly, I implement the didReceive data function like this:
func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive data: Data){
print(data)
}
However, the function is never being called.
I run my session like this:
let session1 = session.dataTask(with: url) { (data, response, error) in
print(data!);
}
It prints the data from the callback, but not from the delegate. Any help is greatly appreciated.
EDIT:
I also added the following:
func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive response: URLResponse,
completionHandler: #escaping (URLSession.ResponseDisposition) -> Void){
completionHandler(URLSession.ResponseDisposition.allow);
}
However, the delegate method is still not being called.
The reason this is not working is that you're creating your data task with a completion handler. Instead you must use the dataTask(with:) function instead.
I also missed this in the documentation and spent hours wondering why my delegate methods weren't being called.
From the docs:
By using the completion handler, the task bypasses calls to delegate methods for response and data delivery, and instead provides any resulting
NSData, URLResponse, and NSError objects inside the completion handler. Delegate methods for handling authentication challenges, however, are still called.
Below is the snippet for making request.
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let configurationId = String(format: "NetworkManager%d", UInt16(arc4random_uniform(UInt32(UINT16_MAX))))
let configuration = URLSessionConfiguration.background(withIdentifier: configurationId)
let session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.current)
let task = session.downloadTask(with: request)
task.resume()
While making this request, the authentication challenge methods as described below are not getting called.
#nonobjc func urlSession(_ session: Foundation.URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
#nonobjc func urlSession(_ session: Foundation.URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
Try using the following header slightly different from the ones you listed in your question.
open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
//handle challenge here.
}