1

I have written a function for a URL request. This contains a completion handler that returns a dictionary of [String: AnyObject] that is fetched from the URL.

The code for this is:

func getDataAsyncFromURLRequest(url: NSURL, completion: ([String : AnyObject]) -> ()) {

    let request = NSMutableURLRequest(URL: url)
    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
        if error != nil {
            print("error=\(error)")
            return
        }
        else {
            let datastring = NSString(data: data!, encoding: NSUTF8StringEncoding)

            if let data = datastring!.dataUsingEncoding(NSUTF8StringEncoding) {
                do {
                    let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! [String : AnyObject]

                    completion(json)

                } catch {
                    print("json error: \(error)")

                }
            }
        }
    }
    task.resume()
}

In some cases, however, I will receive an array of [String : AnyObject] and not the dictionary. So instead of making a duplicate function that takes the array of dictionaries as parameter for the completion handler, I though it was possible to do like this

func getDataAsyncFromURLRequest<T>(url: NSURL, completion: (T) -> ()) { 
    // code here
}

... and then do like this let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! T, but that gives me this error: Cannot invoke 'getDataAsyncFromURLRequest' with an argument list of type '(NSURL, completion: (_) -> ())'

What would be the best way to make the completion handler accept a parameter with a type decided at runtime, if possible at all?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Benjamin Hviid
  • 463
  • 2
  • 5
  • 13

1 Answers1

1

It's very easy why don't you use AnyObject

func getDataAsyncFromURLRequest(url: NSURL, completion: (AnyObject) -> ()) {

    let request = NSMutableURLRequest(URL: url)
    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
        if error != nil {
            print("error=\(error)")
            return
        }
        else {
            let datastring = NSString(data: data!, encoding: NSUTF8StringEncoding)

            if let data = datastring!.dataUsingEncoding(NSUTF8StringEncoding) {
                do {
                    let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())

                    completion(json)

                } catch {
                    print("json error: \(error)")

                }
            }
        }
    }
    task.resume()
}

And result of JSONObjectWithData can be [AnyObject] (Array) or [String:AnyObject] and tree of those items.

So after got result, you can also check type of result in completion block

Like this

if result is [String:AnyObject]
... else if result is [AnyObject] ... else //throw error : because then it is not JSON
Alex
  • 616
  • 4
  • 11