SWIFT: session.dataTaskWithURL - ios

I am trying to follow a tutorial on Swift, but the code does not work in Swift 3. Can anyone help update the code?
let url = NSURL(string: path)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!) {
(data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
print(">>>>> \(data)")
}
I have tried following the suggestions by the compiler, and have changed several of the keywords. The code now looks like this:
let url = NSURL(string: path)
let session = URLSession.shared
let task = session.dataTaskWithURL(url! as URL) {
(data: NSData?, response: URLResponse?, error: NSError?) -> Void in
print(">>>>> \(data)")
}
The error message is:
Cannot convert value of type '(NSData?, URLResponse?, NSError?) -> Void' to expected argument type '(Data?, URLResponse?, Error?) -> Void'
Source Tutorial: Build a simple weather App https://www.youtube.com/watch?v=AoYTuhWZFqM&list=PLoN_ejT35AEjBQ33-L8h2IwG11amXssGk#t=540.527064

let url = URL(string:path)
let session = URLSession.shared
let task = session.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
print()
}

Related

Mocking URLSession for API Testing is giving unrecognized selector sent to instance

I want to test an API without making a server call so I am mocking URLSession and URLSessionDataTask so that I can inject it in my API class.
class MockURLSession: URLSession {
private let mockTask: MockTask
var cachedUrl: URL?
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
mockTask = MockTask(data: data, urlResponse: urlResponse, error:
error)
}
override func dataTask(with url: URL, completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
self.cachedUrl = url
mockTask.completionHandler = completionHandler
return mockTask
}
}
class MockTask: URLSessionDataTask {
private let data: Data?
private let urlResponse: URLResponse?
var completionHandler: ((Data?, URLResponse?, Error?) -> Void)!
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
self.data = data
self.urlResponse = urlResponse
}
override func resume() {
DispatchQueue.main.async {
self.completionHandler(self.data, self.urlResponse, self.error)
}
}
}
Here when I am running this test it's going in my API class calling the getMovies method. Instance I am getting over there is kind of MockURLSession which is fine. Next moment it gives this ApiTests testGetMoviesSuccessReturnsMovies] : failed: caught "NSInvalidArgumentException", "-[MyAppTests.MockTask error]: unrecognized selector sent to instance 0x600002010500
func testGetMoviesSuccessReturnsMovies() {
let jsonData = "[{\"title\": \"Spider Man Far From Home\",\"detail\": \"The first Spider-Man featuring Tom Holland in the iconic role\"}]".data(using: .utf8)
var mockURLSession = MockURLSession(data: jsonData, urlResponse: nil, error: nil)
let apiRespository = APIRepository(session: mockURLSession)
let moviesExpectation = expectation(description: "movies")
var moviesResponse: Result<[Movie]>?
apiRespository.getMovies { (movies) in
moviesResponse = movies
moviesExpectation.fulfill()
}
waitForExpectations(timeout: 10) { (error) in
XCTAssertNotNil(moviesResponse)
}
}
Here is my protocol extension for api
extension Gettable {
func get<T:Decodable>(with decodingType: T.Type, url: String, session: URLSession, completion:#escaping(Result<T>) -> Void) {
let dataTask = session.dataTask(with: URL(string: url)!) { (data, response, error) in
guard data != nil && error == nil else {
return
}
do {
let decoder = JSONDecoder()
let parsedObj = try decoder.decode(T.self, from: data ?? Data())
completion(Result.success(parsedObj))
}
catch let parsedError {
completion(Result.failure(parsedError))
}
}
dataTask.resume()
}
}
Your help will be highly appreciated.
You are not overriding the method dataTask(with:completionHandler:) in your MockURLSession. So, the original dataTask(with:completionHandler:) of URLSession is called, which internally calls dataTaskForRequest:completion:.
If you are successfully overriding existing methods in the parent class, Swift compiler claims to prefix override keyword.
Move your nested dataTask(with:completionHandler:) out of init(data:urlResponse:error:).
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
mockTask = MockTask(data: data, urlResponse: urlResponse, error:
error)
}
override func dataTask(with url: URL, completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
self.cachedUrl = url
mockTask.completionHandler = completionHandler
return mockTask
}
For edited part...
Seems inheritance of error property is not working properly. (Which may be a bug of Swift compiler related to bridging NSError and Error.)
Please try this:
class MockTask: URLSessionDataTask {
private let data: Data?
private let urlResponse: URLResponse?
private let _error: Error?
override var error: Error? {
return _error
}
var completionHandler: ((Data?, URLResponse?, Error?) -> Void)!
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
self.data = data
self.urlResponse = urlResponse
self._error = error
}
override func resume() {
DispatchQueue.main.async {
self.completionHandler(self.data, self.urlResponse, self.error)
}
}
}

App sudden crash loading url

I have the following function to load data. The function worked just fine till a couple of days ago. The app crashes trying to load any url, see code below and screenshot. Coding ios/swift just a few days a year, it pretty hard to figure out what's wrong...
class func loadDataFromURL(_ url: URL, completion:#escaping (_ data: Data?, _ error: NSError?) -> Void) {
let session = URLSession.shared
// Use NSURLSession to get data from an NSURL
let loadDataTask = session.dataTask(with: url, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
if let responseError = error {
completion(nil, responseError)
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode != 200 {
let statusError = NSError(domain:"com.xyz", code:httpResponse.statusCode, userInfo:[NSLocalizedDescriptionKey : "HTTP status code has unexpected value."])
completion(nil, statusError)
} else {
completion(data, nil)
}
}
} as! (Data?, URLResponse?, Error?) -> Void)
loadDataTask.resume()
}
Use below code with latest Swift 3.0 syntax it works on Xcode 8.2:-
func loadDataFromURL(_ url: URL, completion:#escaping (_ data: Data?, _ error: NSError?) -> Void) {
let session = URLSession.shared
// Use NSURLSession to get data from an NSURL
let loadDataTask = session.dataTask(with: url) { (data, response, error) in
if let responseError = error {
completion(nil, responseError as NSError?)
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode != 200 {
let statusError = NSError(domain:"com.xyz", code:httpResponse.statusCode, userInfo:[NSLocalizedDescriptionKey : "HTTP status code has unexpected value."])
completion(nil, statusError)
} else {
completion(data, nil)
}
}
}
loadDataTask.resume()
}

I cannot fix EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) in Swift xcode 8.1 on Json

I am studying the swift and I update the xcode to current version (8.1). So the source that I saved was changed. When I ran the code. It cracked and I cannot fixed it. It showed "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" on the last line. This is a code that I have studied from web.
Thank you very much.
let urlString = "http://swapi.co/api/people/1/"
let session = URLSession.shared
let url = URL(string: urlString)!
session.dataTask(with: url, completionHandler: { (data: Data?, response:URLResponse?, error: NSError?) -> Void in
if let responseData = data {
do {
let json = try JSONSerialization.jsonObject(with: responseData, options: JSONSerialization.ReadingOptions.allowFragments)
if let dict = json as? Dictionary<String, AnyObject> {
if let name = dict["name"] as? String, let height = dict["height"] as? String, let birth = dict["birth_year"] as? String, let hair = dict["hair_color"] as? String {
let person = SWPerson(name: name, height: height, birthYear: birth, hairColor: hair)
print(person.name)
print(person.height)
print(person.hairColor)
print(person.birthYear)
if let films = dict["films"] as? [String] {
for film in films {
print(film)
}
}
}
}
} catch {
print("Could not serialize")
}
}
} as! (Data?, URLResponse?, Error?) -> Void) .resume()
You can save much time if you simply read the documentation
Press ⇧⌘0 (zero, not O)
Type dataTask, select dataTask(with:completionHandler:) and press return.
You will get
func dataTask(with url: URL,
completionHandler: #escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
Do you see the slightly difference in the error parameter?
So the correct syntax in your code is
session.dataTask(with: url, completionHandler: { (data: Data?, response:URLResponse?, error: Error?) -> Void in
...
}).resume()
There is no type cast at the end.
Further the type annotations in the completion block are not needed because the compiler infers the types. The error doesn't occur if you just write
session.dataTask(with: url, completionHandler: { (data, response, error) in
...
}).resume()
The shortest form is using the trailing closure syntax
session.dataTask(with: url) { (data, response, error) in
...
}.resume()

Swift to Swift 2 and Cannot Invoke error. What is wrong?

I am using an API that provided the following code that is supposed to provide the song currently playing on the radio station.
func getSongs() {
let url = NSURL(string: "http://api.vicradio.org/songs/current")!
let request = NSMutableURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data: NSData!, response: NSURLResponse!, error: NSError!) in
if error != nil {
// Handle error...
return
}
println(error)
println(response)
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}
task.resume()
}
This code was written for Swift 1 I believe. I'm getting an error that says:
Cannot invoke "dataTaskWithRequest" with an argument of list type "NSMutableURLRequest, (NSData!, NSURLResponse!, NSError!) -> _ "
I'm rather new to Swift, so maybe someone could explain how I could correct this error?
Change:
(data: NSData!, response: NSURLResponse!, error: NSError!)
to:
(data: NSData?, response: NSURLResponse?, error: NSError?)

Extra argument 'completionHandler' in call with NSURLSession.sharedSession()

I'm new to swift, I am trying to make a weather app in IOS using swift,
When I the NSURLSession and NSURLSession.sharedSession(), I cant run the app its showing this Extra argument 'completionHandler' in call, What may the cause of this error?
my code:
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL, completionHandler:
{ (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void! in
println(response)
})
downloadTask.resume()
Use dataTaskWithRequest.
Here is a sample how i download image
var dowloadTask = session.dataTaskWithRequest(urlRequest, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
// data to image
let image = UIImage(data: data)
if image != nil {
// do some stuff
// preview
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.image = image
})
}
})
dowloadTask.resume()
let sharedSession = NSURLSession.sharedSession()
let url = NSURL(string: "")
let task = sharedSession.downloadTaskWithURL(url!, completionHandler: {(location: NSURL!, response: NSURLResponse!, error: NSError!) in
println("Task completed")
})
task.resume()

Resources