Home > Software engineering >  Trying to retrieve boolean value from a function in swift
Trying to retrieve boolean value from a function in swift

Time:08-27

I am trying to get a variable from the function that represents the boolean status of the charge_port_door_open variable, something like this: let ChargePortStatus = (DATA.response.charge_state.charge_port_door_open) The function does print a correct boolean, however, 'DATA' cannot be found in scope outside the function.

Edit: Thank you all very much for the help! This is my first question posted on this website and I wasnt expecting for help to arrive so quickly!

import Foundation
import UIKit

struct Root: Codable {
let response: TEST1
}

struct TEST1: Codable {
let charge_state: TEST2
}

struct TEST2: Codable {
let charge_port_door_open: Bool
}

public func RequestVehicleData() {
 
    let url = URL(string: "https://owner-api.teslamotors.com/api/1/vehicles/:id/vehicle_data")!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue( "Bearer \(token)", forHTTPHeaderField: "Authorization")

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
    let DATA = try! JSONDecoder().decode(Root.self, from: data!)
    print(DATA.response.charge_state.charge_port_door_open)            
}
        task.resume()
}

CodePudding user response:

Since dataTask is asynchronous, you have to modify your method to return a value in a closure. A simple version without any error handling can look like this:

public func requestVehicleData(completion: @escaping ((Bool?) -> Void) {
    let url = URL(string: "https://owner-api.teslamotors.com/api/1/vehicles/:id/vehicle_data")!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue( "Bearer \(token)", forHTTPHeaderField: "Authorization")

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let responseData = data, let response = try? JSONDecoder().decode(Root.self, from: responseData) {
            completion(response.response.charge_state.charge_port_door_open)        
        } else {
            completion(nil)
        }
    }

    task.resume()
}

You can also play around with the Swift Concurrency and user new async/await API for the same purpose.

P.S. When you have a chance, take a look at some basics and API Design Guideline.

CodePudding user response:

Two simple approaches (if you don't want the call-site to have to use a completion block - which is also a perfectly good solution described in Maksym's answer) are..

  1. perform any actions you need to perform with the value inside of the closure

  2. create an optional property with a didSet on whatever owns RequestVehicleData. That way you can set the value within the closure and trigger the desired actions. An example for this would be:

    class VehicleDataManager {
        private var root: Root? {
            didSet {
                doSomething(with: root)
            }
        }
    
        public func RequestVehicleData() {
    
            let url = URL(string: "https://owner-api.teslamotors.com/api/1/vehicles/:id/vehicle_data")!
            var request = URLRequest(url: url)
            request.httpMethod = "GET"
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
            request.setValue( "Bearer \(token)", forHTTPHeaderField: "Authorization")
    
            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                root = try! JSONDecoder().decode(Root.self, from: data!)
                print(DATA.response.charge_state.charge_port_door_open)            
            }
            task.resume()
         }
    }
    

The value is fetched asynchronously, so it will only be safely accessible in places that are guaranteed to get run after it has been returned.

Side note: I know this might have just been for the sake of a "quick and dirty" test function, but I would highly recommend not getting in the habit of force-unwrapping values that very well could be nil

  • Related