-2

Sup, everyone... i hope you're doing good. Well, I've being coding for a short period of time and this bug came across, does anyone knows how to solve it? The intention is to have this 'file' which is a 'Auth Service', to communicate with a 'user data service' when the user present all of the information to this chat app.

The Third Image that I uploaded is what the I've being taught to to do it.*

AF.request(URL_USER_ADD, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in

  switch response.result {
          case .success(let result):
             if let json = result as? Data {
                guard let data = response.data else { return }
                guard let json = JSON(data: data) else { return }
                let id = json["_id"].stringValue
                let color = json["avatarColor"].stringValue
                let avatarName = json["avatarName"].stringValue
                let email = json["email"].stringValue
                let name = json["name"].stringValue
             }

            case .failure(let result):
                completion(false)
                debugPrint(response.result as Any)

                UserDataService.instance.setUserData(id: _id, color: avatarColor, avatarName: avatarName, email: email, name: name)
                completion(true)
            }
        }
    }
}

error01

error02

lesson taught

vadian
  • 274,689
  • 30
  • 353
  • 361
goat23
  • 3
  • 1
  • 3
  • The errors mean exactly what they say. The `JSON` initialiser does not return `nil` if the decoding fails. Rather, it `throws` an exception. You need to wrap the call in a `do/try/catch` clause so that you can handle any error – Paulw11 Apr 02 '21 at 20:45
  • The second error just seems to be misplaced code; you are trying to access local variables declared in the `.success` case outside of that code block. The variable name is also `id`, not `_id` – Paulw11 Apr 02 '21 at 20:47

2 Answers2

0

It would seem that the JSON initialiser throws, so the compiler is telling you you need to handle this.

You are also trying to access local variables declare in the .success code block outside of that block, so they are unknown. You also have the wrong name for the id variable.

AF.request(URL_USER_ADD, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in

  switch response.result {
          case .success(let result):
             if let json = result as? Data {
                guard let data = response.data else { return }
                do {
                    let json = try JSON(data: data)
                    let id = json["_id"].stringValue
                    let color = json["avatarColor"].stringValue
                    let avatarName = json["avatarName"].stringValue
                    let email = json["email"].stringValue
                    let name = json["name"].stringValue
                    UserDataService.instance.setUserData(id: id, color: avatarColor, avatarName: avatarName, email: email, name: name)
                    completion(true)
                } catch {
                    print(error)
                    completion(false)
                }
            }

            case .failure(let result):
                completion(false)
                debugPrint(response.result as Any)
            }
        }
    }
}

As a point of style, a completion handler that simply returns true or false isn't particularly useful as it doesn't provide any information on what went wrong when false is returned, but since you mention a lesson, I will assume that this isn't your design choice.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • no it isn't. I'm just trying to replicate what he asked me to do it. Even reading as much as I can, I don't understand much, but I'm deeply trying! – goat23 Apr 02 '21 at 23:43
0

It seems this bit of code is part of a popular programming course or something, because I answered another post.

Your teacher's code is wrong because it doesn't handle the throwing initializer for JSON. Perhaps it was right for some earlier version of SwiftyJSON. In any case @Paulw1's answer gets you most of the way there. The problem is that simply calling try JSON(data: data) will be a problem if the surrounding function isn't marked as throws. Given that you're already bailing out with some other errors (such as failing to unwrap optionals), and that is apparently acceptable because it's what your teacher's code does, you can do it like this:

guard let json = try? JSON(data: data) else { return }

So here's the deal on try and it's variants.

try

For try, either the surrounding function must be marked throws, in which case, any error thrown will propagate up to the caller, or you have to explicitly handle it in a do...catch.

So if we assume that your function is called foo, it would need to be declared something like this:

 func foo(...) throws -> ReturnTypeIfAny

or you have to wrap the try in a do...catch like this:

let json: JSON
do {
    json = try JSON(data: data)
}
catch {
    // do something with the error
}

try?

try? returns nil if the thing that can throw does throw. So you handle it like any optional return type.

guard let json = try? JSON(data: data) else { return }

or

if let json = try? JSON(data: data)
{
   // code that access json goes here
}

try!

You probably want to avoid this one most of the time. try! completely ignores the possibility of an error being thrown and crashes if one is thrown. Use it only when you are sure that even though the function you're calling is marked as throws, you know it can't actually throw.

This can happen when the reason it's marked as throws because it's part of a protocol conformance, but the thing you're calling is something you wrote, and in your case, you know it doesn't ever throw. In that case try! is OK. But if it's not your code you're calling, or if you're in doubt, always assume that any function marked throws can actually throw, so you need to handle it.

Chip Jarred
  • 2,600
  • 7
  • 12