How to use NSURLSessionDataTask in Swift
It's unclear what you're asking, but I noticed that you have a couple of errors in the code:
You should create your
session
usingNSURLSession(configuration: config)
session.dataTaskWithRequest
returns aNSURLSessionDataTask
, so there's no need to wrap it insideNSURLSessionDataTask()
(a.k.a instantiating a newNSURLSessionDataTask
object).The completion handler is a closure and here's how you create that particular clousure:
{(data : NSData!, response : NSURLResponse!, error : NSError!) in
// your code
}
Here's the updated code:
let url = NSURL(string: "https://itunes.apple.com/search?term=\(searchTerm)&media=software")
let request = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
// notice that I can omit the types of data, response and error
// your code
});
// do whatever you need with the task e.g. run
task.resume()
How to use NSURLsession and its delegate methods
YOU CAN DO LIKE THIS:
//GET REQUEST CODE
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
// NSURLSession *s = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"PUT_YOUR_URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//
if (data) {
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse*)response;
NSInteger statusCode = httpResponse.statusCode;
if (statusCode == 200) {
//PERFORM YOUR OPERATIONS
}
}else if (error)
{
NSLog(@"Errorrrrrrr....");
}
}];
[dataTask resume];
How to get data from a Swift NSURLSession?
I'm not sure NSString is the type you want. JSON may be format of the data returned, depending on your URL's functionality. I tried the code provided and got the same issues, but if you treat it as JSON (I used httpbin.org as a dummy URL source) and it worked.
let task = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://httpbin.org/get")!, completionHandler: { (data, response, error) -> Void in
do{
let str = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! [String:AnyObject]
print(str)
}
catch {
print("json error: \(error)")
}
})
task.resume()
(thanks for suggested edit @sgthad. the edit is not particularly relevant to the question, but still wanted to update the code to be current.)
Update for Swift 3 syntax
let url = URL(string: "http://httpbin.org/get")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let unwrappedData = data else { return }
do {
let str = try JSONSerialization.jsonObject(with: unwrappedData, options: .allowFragments)
print(str)
} catch {
print("json error: \(error)")
}
}
task.resume()
Swift 2 How do I wait for NSURLSessionDataTask to complete before continuing code
The proper way to do this is to add a completion handler
func sendRequest(completion: () -> Void) {
// ...
let task = session.dataTaskWithRequest(request) {
// ...
completion()
}
task.resume()
}
Usage:
let r = Request()
r.sendRequest {
// It's done, do something
}
If you insist on blocking the thread (I hope it's not the main thread), use a semaphore. But remember to signal semaphore whether the request succeeded or failed. I've seen far too many code that forgot to signal the semaphore when the request fail so the app just hung up.
func sendRequest() {
let semaphore = dispatch_semaphore_create(0)
let task = session.dataTaskWithRequest(request) {
// ...
dispatch_semaphore_signal(semaphore)
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}
Testing NSURLSession resume cannot be sent to abstract instance of class NSURLSessionDataTask
HERE someone rewrote the article and you can test below code in Playground:
import UIKit
import XCTest
import PlaygroundSupport
import Foundation
// Protocol for MOCK/Real
protocol URLSessionProtocol {
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}
protocol URLSessionDataTaskProtocol {
func resume()
}
//MARK: HttpClient Implementation
class HttpClient {
typealias completeClosure = ( _ data: Data?, _ error: Error?)->Void
private let session: URLSessionProtocol
init(session: URLSessionProtocol) {
self.session = session
}
func get( url: URL, callback: @escaping completeClosure ) {
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = session.dataTask(with: request) { (data, response, error) in
callback(data, error)
}
task.resume()
}
}
//MARK: Conform the protocol
extension URLSession: URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping URLSessionProtocol.DataTaskResult) -> URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTask
}
}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}
//MARK: MOCK
class MockURLSession: URLSessionProtocol {
var nextDataTask = MockURLSessionDataTask()
var nextData: Data?
var nextError: Error?
private (set) var lastURL: URL?
func successHttpURLResponse(request: URLRequest) -> URLResponse {
return HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
}
func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
lastURL = request.url
completionHandler(nextData, successHttpURLResponse(request: request), nextError)
return nextDataTask
}
}
class MockURLSessionDataTask: URLSessionDataTaskProtocol {
private (set) var resumeWasCalled = false
func resume() {
resumeWasCalled = true
}
}
//MARK: Test
class HttpClientTests: XCTestCase {
var httpClient: HttpClient!
let session = MockURLSession()
override func setUp() {
super.setUp()
httpClient = HttpClient(session: session)
}
override func tearDown() {
super.tearDown()
}
func test_get_request_with_URL() {
guard let url = URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json") else {
fatalError("URL can't be empty")
}
httpClient.get(url: url) { (success, response) in
// Return data
}
XCTAssert(session.lastURL == url)
}
func test_get_resume_called() {
let dataTask = MockURLSessionDataTask()
session.nextDataTask = dataTask
guard let url = URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json") else {
fatalError("URL can't be empty")
}
httpClient.get(url: url) { (success, response) in
// Return data
}
XCTAssert(dataTask.resumeWasCalled)
}
func test_get_should_return_data() {
let expectedData = "{}".data(using: .utf8)
session.nextData = expectedData
var actualData: Data?
httpClient.get(url: URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json")!) { (data, error) in
actualData = data
}
XCTAssertNotNil(actualData)
}
}
HttpClientTests.defaultTestSuite.run()
How to get data to return from NSURLSessionDataTask in Swift
With the help and suggestion taken from Abizern I finally managed how to write up this block or closure if you want.
So what worked for me in the end:
The GetHomeData function I changed as follows:
private let siteContent:String = "http://www.imoc.co.nz/MobileApp/HomeContent"
// I changed the signiture from my original question
func GetHomeData(completionHandler: ((NSDictionary!) -> Void)?)
{
var url : NSURL! = NSURL(string:siteContent)
var request: NSURLRequest = NSURLRequest(URL:url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary!
// then on complete I call the completionHandler...
completionHandler?(jsonResult?);
});
task.resume()
}
Then I call the function like this:
/*Call to go get home page content*/
func SetHomeContent()
{
homeModel.GetHomeData(self.resultHandler)
}
func resultHandler(jsonResult:NSDictionary!)
{
let siteContent = jsonResult.objectForKey("SiteContent") as NSDictionary
let paraOne = siteContent.objectForKey("HomePageParagraphOne") as String
}
Related Topics
Uiview Hide/Show with Animation
In iOS 12, When Does the Uicollectionview Layout Cells, Use Autolayout in Nib
Choosing the Right iOS Xml Parser
Passing Data to View Controllers That Are Embedded in Container Views
Swift - Check If a Timestamp Is Yesterday, Today, Tomorrow, or X Days Ago
Adding Navigation Bar Programmatically iOS
Nstimer Timerwithtimeinterval: Not Working
Using Weak Self in Dispatch_Async Function
Tweening/Interpolating Between Two Cgpaths/Uibeziers
Check If Optional Array Is Empty
Ibeacon Notification When the App Is Not Running
Force Landscape Mode in One Viewcontroller Using Swift
Save Images with Phimagemanager to Custom Album
Creating Custom Info Window in Swift with the Google Maps iOS Sdk
iOS UI Testing on an Isolated View
How to Create Custom Mkannotationview and Custom Annotation Title and Subtitle