Lory Lory Lory Lory - 2 months ago 90
Swift Question

Many problems with Swift3: cannot understand new syntax for completion handlers

Yesterday I updated to new Mac OS X Sierra and XCode 8 which forced me to update to Swift 3.0 syntax. In my app I have many functions like the following:

fileprivate func requestFisheFieldWithHandler(_ url:String, completionHandler: @escaping (_ success: NSDictionary?, _ error: NSError?) -> Void) {

let configuration = URLSessionConfiguration.default

let url: URL = URL(string: url)!
let urlRequest: URLRequest = URLRequest(url: url)

let session = URLSession(configuration: configuration)

let task = session.dataTask(with: urlRequest, completionHandler: { (data: Foundation.Data?, response: URLResponse?, error: NSError?) -> Void in

if (error != nil) {
//print(error?.code)
//print(error)
completionHandler(success: nil, error: error)
}

else {
do {
let responseJSON = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [String: String]
completionHandler(success: responseJSON, error:nil)
}
catch let error as NSError {
completionHandler(success: nil, error:error)
}
}
} as! (Data?, URLResponse?, Error?) -> Void)

task.resume()
}


and I get this error:

"Cannot convert value of type '(Data?, URLResponse?, Error?) -> Void' to expected argument type '(Data?, URLResponse?, Error?) -> Void'"

Moreover, I also used many associative arrays to collect data from downloaded JSON file, like the following:

for comune in response! {
self.comuni.append(comune["nome"] as! String)
self.comuniWithID[comune["nome"] as! String] = Int(comune["idcomune"] as! String)
}
DispatchQueue.main.async {
self.myPicker.reloadComponent(1)
}


and another error I get is:

"Type 'NSFastEnumerationIterator.Element' (aka 'Any') has no subscript members"

Please, would someone help me to correct them? Because I cannot understand what they mean and my app will be published next 30th Semptember...

Answer

The most significant change is that all parameter labels in closures have been removed in Swift 3.

This is your code Swift 3 compatible.

As always, do not cast a Swift collection type to a Foundation counterpart. You will throw away all type information.

And don't use the annotations in the completion block return values, the compiler can infer the types. If you need to look up the actual types ⌥-click on the symbol.

fileprivate func requestFisheFieldWithHandler(_ url:String, completionHandler: @escaping ([String: String]?, NSError?) -> Void) {

  let configuration = URLSessionConfiguration.default

  let url: URL = URL(string: url)!
  let urlRequest = URLRequest(url: url)

  let session = URLSession(configuration: configuration)

  let task = session.dataTask(with: urlRequest) { (data, response, error) -> Void in
    if (error != nil) {
      completionHandler(nil, error as NSError?)
    }

    else {
      do {
        let responseJSON = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [String: String]
        completionHandler(responseJSON, nil)
      }
      catch let error as NSError {
        completionHandler(nil, error)
      }
    }
  }
  task.resume()
}

Regarding the second error you have to cast response! to something more meaningful than Any, I guess ... in response as! [[String:Any]]

Comments