Invalid conversion from throwing function of type - swift

I am trying to convert my code over to Swift 2 and I am having issues with this last function. I get the follow error on the declaration of task:
Invalid conversion from throwing function of type ... to non throwing type.
func performSearch(searchTerm: String){
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(urlForQuery(searchTerm)!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
do {
let result: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
}
let results: AnyObject? = result.objectForKey("results")
if let testVar: NSMutableArray = results as? NSMutableArray {
// Uncomment this to print all feeds
//println(testVar)
self.searchedPodcasts.removeAllObjects()
self.searchedPodcasts.addObjectsFromArray(testVar as [AnyObject])
NSNotificationCenter.defaultCenter().postNotificationName("SearchPerformed", object: self)
}
})
task!.resume()
}
I have tried the following but it doesn't work either and it also means I can't call task.resume for some reason:
func performSearch(searchTerm: String){
let session = NSURLSession.sharedSession()
do {
let task = session.dataTaskWithURL(urlForQuery(searchTerm)!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
do {
let result: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
}
let results: AnyObject? = result.objectForKey("results")
if let testVar: NSMutableArray = results as? NSMutableArray {
// Uncomment this to print all feeds
//println(testVar)
self.searchedPodcasts.removeAllObjects()
self.searchedPodcasts.addObjectsFromArray(testVar as [AnyObject])
NSNotificationCenter.defaultCenter().postNotificationName("SearchPerformed", object: self)
}
})
} catch {
print("error)
}
task!.resume()
}
What can I do to fix it?
Edit: Tried this but the same error is still returned.
func test(searchTerm: String) {
let session = NSURLSession.sharedSession()
do {
let task = try session.dataTaskWithURL(urlForQuery(searchTerm)!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
let result: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
})
} catch {
print("hello")
}
}

Try adding a catch block to your do-try-catch sentence:
do {
let result: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
}
catch {
print("error");
}
You'll also need to declare the result variable outside or move more code inside the do block.
For more info about exception handling in Swift 2 check out this guide.

Apple replaced NSError with ErrorType in Swift 2.
So replace your own explicit usage of NSError with ErrorType and you don't need the additional try catch block suggested in the other answer and you can express your error handling with much less code.

Related

how to pass variable value to outside of URLSession async - swift 3

I have this code :
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil {
print(error!)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let getDetail = parseJSON["detail"] as? String
returnDetail = getDetail!.base64Decoded()
} // parse json end
} // do end
catch {
print(error)
}
} // let task end
returnDetail has been defined previously. I did anything to set returnDetail value to getDetail!.base64Decoded() but it only works inside let task = ...
How can I pass it to the outer scope?
You have several methods to tackle the issue of returning a value from inside an asynchronous function. One of them is to wrap the asynchronous network call inside a function and make it return a completionHandler.
Some general advice: don't use force unwrapping unless you are 100% sure that your optional value won't be nil. With network requests, the data can be nil even if there's no error, so never force unwrap data, use safe unwrapping with if let or guard let. Don't use .mutableContainers in Swift when parsing a JSON value, since it has no effect. The mutability of the parsed JSON object is decided by using the let or var keyword to declare the variable holding it. Also don't use NSDictionary, use its native Swift counterpart, Dictionary ([String:Any] is a shorthand for the type Dictionary<String,Any>).
func getDetail(withRequest request: URLRequest, withCompletion completion: #escaping (String?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil {
completion(nil, error)
return
}
else if let data = data {
do {
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else {completion(nil, nil);return}
guard let details = json["detail"] as? String else {completion(nil, nil);return}
completion(details, nil)
}
catch {
completion(nil, error)
}
}
}
task.resume()
}
Then you can call this function by
getDetail(withRequest: request, withCompletion: { detail, error in
if error != nil {
//handle error
} else if detail = detail {
//You can use detail here
}
})
I would suggest to use a completion handler.
func foo(withCompletion completion: (String?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil {
completion(nil, error)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let details = parseJSON["detail"] as? String
completion(details, nil)
} // parse json end
} // do end
catch {
completion(nil, error)
}
} // let task end
}
I think, you use CallBack(Clourse) of Swift to return data when getDetail have data.

Cast from 'NSManagedObject' to unrelated type always fails

I'm trying to load data and save it into the database but I get a warning and an error in func preloadData():
Cast from 'NSManagedObject' to unrelated type 'LeadItem' always fails
And in func removData():
cannot convert value of type 'LeadItem' to expected argument type 'NSManagedObject'
Similar solutions for an older version of Xcode aren't working for me.
func preloadData ()
{
if let contentsOfURL = NSBundle.mainBundle().URLForResource("leads_Data", withExtension: "csv")
{
removeData()
var error:NSError?
if let leads = parseCSV(contentsOfURL, encoding: NSUTF8StringEncoding, error: &error)
{
for lead in leads
{
let leadItem = NSEntityDescription.insertNewObjectForEntityForName("LeadItem", inManagedObjectContext: self.managedObjectContext) as! LeadItem
}
}
}
}
func removeData ()
{
let fetchRequest = NSFetchRequest(entityName: "LeadItem")
do
{
let leadItems = try self.managedObjectContext.executeFetchRequest(fetchRequest) as! [LeadItem]
for leadItem in leadItems
{
self.managedObjectContext.deleteObject(leadItem)
}
}
catch let error as NSError
{
print("Failed to retrieve record: \(error.localizedDescription) \n")
}
}
}

Invalid conversion from throwing function of type '(NSData!, NSError!) throws -> ()' to non-throwing function type '(NSData!, NSError!) -> Void'

I was trying to convert from Swift 1 to 2 in the line if let jsonData Array = try NSJSONSerialization... because it was originally giving me an error from the "extra argument 'error' in call" so I added the "try" before NSJSONSerialization but now it's saying "Invalid conversion from throwing function of type '(NSData!, NSError!) throws -> ()' to non-throwing function type '(NSData!, NSError!) -> Void'. I think the error isn't handled properly but I don't know how to do that. Here's the code
httpHelper.sendRequest(httpRequest, completion: {(data:NSData!, error:NSError!) in
if error != nil {
let errorMessage = self.httpHelper.getErrorMessage(error)
let errorAlert = UIAlertView(title:"Error", message:errorMessage as String, delegate:nil, cancelButtonTitle:"Ok")
errorAlert.show()
return
}
var error: NSError?
// let jsonDataDict = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &error) as! NSDictionary
// let jsonDataDict = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) as! NSDictionary
if let jsonDataArray = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) as? NSArray! {
//load collection view with selfies
if jsonDataArray != nil {
for imageDataDict in jsonDataArray {
var selfieImgObj = SelfieImage()
selfieImgObj.imageTitle = imageDataDict.valueForKey("title") as! String
selfieImgObj.imageId = imageDataDict.valueForKey("random_id") as! String
selfieImgObj.imageThumbnailURL = imageDataDict.valueForKey("image_url") as! String
self.dataArray.append(selfieImgObj)
}
self.collectionView?.reloadData()
}
}
})
}
First, you should be wrapping any functions that call throws in a do-try-catch loop. Secondly, safely unwrap the jsonArray as a Swift Array rather than trying to force cast it to an NSArray:
do {
if let jsonArray = try NSJSONSerialization.JSONObjectWithData(NSData(), options: .AllowFragments) as? [AnyObject] {
// unarchived data is an array
}
} catch {
print(error)
}

JSON is not convertible to void (Openweather map API)

I am calling Openweather map API using Swift and from the response I need to return a particular value as string.
However when I try to return the value error comes as JSON is not convertible to string.
func callWeatherServ(name:String, completion:(Dictionary<String,AnyObject>) -> Void)
{
var baseUrl: String = "http://api.openweathermap.org/data/2.5/weather"
var url: String = "\(baseUrl)?q=\(name)"
let finalUrl: NSURL = NSURL(string: url)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(finalUrl, completionHandler: {data, response, error -> Void in
if error != nil
{
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as! NSDictionary
if err != nil
{
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
let json = JSON(jsonResult)
println("response is \(json) ")
var weathername = json["weather"][0]["main"]
if (weathername != nil)
{
return weathername
}
})
task.resume()
}
I get that since we have used closure whose return type void so we should use completion handler. But I am not aware how we can do that.
Also how we can call the function if we pass completion handler as parameter?
If you want to keep using SwiftyJSON as in your example, here's how to do it:
change the type of the completion handler from a dictionary to the JSON type used by SwiftyJSON.
then wrap the value you want to "return" in the handler.
then call your method as in my example, with a trailing closure
Swift 2
func callWeatherServ(name:String, completion:(object: JSON) -> Void) {
let baseUrl: String = "http://api.openweathermap.org/data/2.5/weather"
let url: String = "\(baseUrl)?q=\(name)"
if let finalUrl = NSURL(string: url) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(finalUrl, completionHandler: {data, response, error -> Void in
if let error = error {
print(error.localizedDescription)
} else {
if let data = data {
let json = JSON(data: data)
print("response is \(json) ")
completion(object: json["weather"][0]["main"])
} else {
print("No data")
}
}
})
task.resume()
}
}
Call the method:
callWeatherServ("paris") { (object) in
// here you get back your JSON object
print(object)
}
Note that you were parsing your data twice, with NSJSONSerialization and with SwiftyJSON, so I've removed the unnecessary NSJSONSerialization part.
Original Swift 1 version
func callWeatherServ(name:String, completion:(object: JSON) -> Void)
{
var baseUrl: String = "http://api.openweathermap.org/data/2.5/weather"
var url: String = "\(baseUrl)?q=\(name)"
let finalUrl: NSURL = NSURL(string: url)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(finalUrl, completionHandler: {data, response, error -> Void in
if error != nil
{
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
let json = JSON(data: data, options: NSJSONReadingOptions.allZeros, error: &err)
println("response is \(json) ")
var weathername = json["weather"][0]["main"]
if (weathername != nil)
{
completion(object: weathername)
}
})
task.resume()
}
Call the method:
callWeatherServ("paris", completion: { (object) -> Void in
println(object) // "Clear"
})
Implement completion handler from where you are calling this method and use the string at that place only no need to return the string.
You can directly use it from the completion handle by implemet it in caller function

How to return NSDictionary in swift, while waiting for its value to be set?

please spare me. Im new to swift
my problem was I cant return my NSDictionary this is my function
private func request(url:String, baseURL:String) -> NSDictionary {
var dict:NSDictionary!
var request = HTTPTask()
request.requestSerializer = HTTPRequestSerializer()
request.requestSerializer.headers[headerKey] = getToken() //example of adding a header value
request.baseURL = baseURL
request.GET(url, parameters: nil, success: {(response: HTTPResponse) in
if var data = response.responseObject as? NSData {
let str = NSString(data: data, encoding: NSUTF8StringEncoding)
var error: NSError?
dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
println("response: \(dict)")
}
},failure: {(error: NSError, response: HTTPResponse?) in
println("error: \(error)")
})
return dict
}
the return dict is just empty like {} but when i println("response: \(dict)") inside the function seem to log my data.
I think my function return an empty object because the .GET method is running in different thread and waiting for a response.
Could anyone help me, any comment would do.
You are right, request runs asynchronously in another thread, I would suggest using completion handler.
private func request(url: String, baseURL: String, completion: (result: NSDictionary) -> Void) {
var dict:NSDictionary!
var request = HTTPTask()
request.requestSerializer = HTTPRequestSerializer()
request.requestSerializer.headers[headerKey] = getToken() //example of adding a header value
request.baseURL = baseURL
request.GET(url, parameters: nil, success: {(response: HTTPResponse) in
if var data = response.responseObject as? NSData {
let str = NSString(data: data, encoding: NSUTF8StringEncoding)
var error: NSError?
dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
println("response: \(dict)")
completion(result: dict)
}
},failure: {(error: NSError, response: HTTPResponse?) in
println("error: \(error)")
completion(result: nil) //this is not the best option, better would be to return error in error handler
})
}
For more info check out this: http://www.veasoftware.com/tutorials/2015/1/13/completion-handlers-swift-programming-tutorial