0

I'm working on an app that features a login screen, which is a first for me. After following different websites that provided tutorials for this, I made a LoginService ViewController that would help with the process of signing in to the app.

Here is a part of the code that I've used in this ViewController:

 // MARK: Private Methods

private func exchangeTokenForUserAccessTokenWithCompletionHandler(username: String, password: String, completion: (OAuthInfo?, error: String?) -> ()) {

    let path = "/oauthfake/token/"
    let url = ConnectionSettings.apiURLWithPathComponents(path)
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "POST"

    var params =  "client_id=\(ConnectionSettings.clientId)&client_secret=\(ConnectionSettings.clientSecret)&grant_type=password&login=\(username)&password=\(password)"

    var err: NSError?
    request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")


    let task = session.dataTaskWithRequest(request) {data, response, error -> Void in

        var err: NSError?
        var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary

        if (err != nil) {

            // Something went wrong, log the error to the console.
            print(err!.localizedDescription)
            let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("Something went wrong: '\(jsonStr)")

            completion(nil, error: err?.localizedDescription)
        } else {
            if let parseJSON = json {
                if let token = parseJSON.valueForKey("access_token") as? String {
                    if var issuedAt = parseJSON.valueForKey("issued_at") as? String {
                        if var tokenExpiresIn = parseJSON.valueForKey("expires_in") as? String {
                            if var refreshTokenIssuedAt = parseJSON.valueForKey("refresh_token_issued_at") as? String {
                                if let refreshToken = parseJSON.valueForKey("refresh_token") as? String {
                                    if var refreshTokenExpiresIn = parseJSON.valueForKey("refresh_token_expires_in") as? String {
                                        if let refreshCount = parseJSON.valueForKey("refresh_count") as? String {

                                            let epochIssuedAt:Double = (issuedAt as NSString).doubleValue / 1000.0
                                            let epochRefreshTokenIssuedAt:Double = (refreshTokenIssuedAt as NSString).doubleValue / 1000.0

                                            let oauthInfo = OAuthInfo(issuedAt: epochIssuedAt, refreshTokenIssuedAt: epochRefreshTokenIssuedAt, tokenExpiresIn: (tokenExpiresIn as NSString).doubleValue, refreshToken: refreshToken, token: token, refreshTokenExpiresIn: (refreshTokenExpiresIn as NSString).doubleValue, refreshCount: (refreshCount as NSString).integerValue)

                                            completion(oauthInfo, error: err?.localizedDescription)

My super.init seems to work fine (not featured above), as well as the rest of the code in this file, but I get one error reading "Extra argument 'error' in call" on this line:

var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary

I have already gathered that Swift 2.0 handles errors differently to what I'm used to. I know that this version of Swift uses try, let and catch codes for errors. My issue is I haven't used any of these types of code before and am unsure on how to use them in this particular situation.

2 Answers2

1

On iOS 7 and latter NSJSONSerialization is thread safe.Now you can use it using do try catch

Swift 3:

do{
let JsonDict = try JSONSerialization.jsonObject(with: data, options:.MutableLeaves)
}
catch let error as NSError {
    print(error)
}

Swift 2:

do{
  let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as! [String:AnyObject]
}catch let error as NSError{
  print(error)
}
Donal
  • 6,082
  • 2
  • 19
  • 30
  • Thanks for the feedback, seeing how you've laid out the syntax has been very helpful! If it's okay to ask (I'm still learning about this, sorry), I wanted to make sure I know where exactly I should put the do try catch code in comparison to the line I had with the NSJSONSerialization error. – R. Osolinski Mar 10 '17 at 19:51
  • @R.Osolinski:Do you want to compare two NSJSONSerialization? – Donal Mar 14 '17 at 07:16
0

The JSONObjectWithData function requires the do try catch syntax you mentioned because the method at its declaration site is marked with the throws keyword. (Documentation here: https://developer.apple.com/reference/foundation/jsonserialization/1418059-jsonobject)

No to use it simply.

do {
try someMethodWhichCanThrow()
catch(error) {
// maybe log the error here
}

This is described in the Swift Programming language book here: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID508

JMFR
  • 799
  • 5
  • 18