Home > database >  Return HTTP request data
Return HTTP request data

Time:12-31

I would like to return the var points from my method getAllPoints()

struct tempPoint: Decodable {
    let idPoint:Int
    let ptName:String
    let ptLat:Double
    let ptLong:Double
}

func getAllPoints(){

if let url = URL(string: "[MyWebService.com]") {
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                if let jsonString = String(data: data, encoding: .utf8) {
                    let jsonData = Data(jsonString.utf8)
                    do {
                        let points = try JSONDecoder().decode([tempPoint].self, from: jsonData)
                    } catch let error {
                        print(error)
                    }
                    print(jsonString)
                }
            }
        }.resume()
    }
}

Results that I got when I do print(points)

[
{"idPoint":6,"ptName":"Maison","ptLat":43.72623997050257,"ptLong":2.202591651830584},
{"idPoint":7,"ptName":"Wheelin","ptLat":42.75754326128173,"ptLong":8.137330631668685},
{"idPoint":8,"ptName":"Animoz","ptLat":45.76321863196126,"ptLong":7.137186047202841},
{"idPoint":9,"ptName":"Hesias","ptLat":45.767222865412144,"ptLong":6.132352002277385},
{"idPoint":10,"ptName":"Marcombes","ptLat":45.76018235160473,"ptLong":4.085466264251463},
{"idPoint":11,"ptName":"Leclan","ptLat":48.80950120948317,"ptLong":2.110623123039061},
{"idPoint":12,"ptName":"Cournon Skatepark","ptLat":39.74138613175866,"ptLong":4.2154977334348906}
]

I wonder if this is possible to return these at the end of my method. I'm gonna use it in a pickerView and to do a CRUD that's why I would like to store them.

Thank You

CodePudding user response:

use completion closure to "return" your points. Try something like this:

func getAllPoints(completion: @escaping([tempPoint]) -> ()) {  // <-- here
    if let url = URL(string: "[MyWebService.com]") {
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                do {
                    let points = try JSONDecoder().decode([tempPoint].self, from: data)
                    completion(points)  // <-- here return the results when done
                    return
                } catch let error {
                    print(error) // <-- here todo deal with errors
                }
            }
            completion([]) // <-- here todo deal with errors
        }.resume()
    } else {
        completion([]) // <-- here todo deal with errors
    }
}

and call the function like this:

getAllPoints() { results in
      print("array of points: \(results)")
}

CodePudding user response:

My understanding is that you wanted the api response at the position of calling your function. You can return your response using closures.

The typealias you are seeing in the below code are self defined data types. You can directly add closures in your function but to make it more simple for you I declare those closures with typealias as data types. You can read more about typealias and closures here.

After declaring our own closure types. We need to use them in our function as parameters.

struct TempPoint: Decodable {
        let idPoint:Int
        let ptName:String
        let ptLat:Double
        let ptLong:Double
    }
    
    typealias ApiResponse = ([TempPoint]) -> Void
    typealias ApiError = (Error) -> Void
    
    func getAllPoints(_ completion: @escaping ApiResponse, apiError: @escaping ApiError){
        
        if let url = URL(string: "[MyWebService.com]") {
            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data {
                    if let jsonString = String(data: data, encoding: .utf8) {
                        let jsonData = Data(jsonString.utf8)
                        do {
                            let points = try JSONDecoder().decode([TempPoint].self, from: jsonData)
                            completion(points)
                        } catch let error {
                            print(error)
                            apiError(error)
                        }
                        print(jsonString)
                    }
                }
            }.resume()
        }
    }

Our function after changes would look like above.

Now here is how we can use this function.

override func viewDidLoad() {
    super.viewDidLoad()
    
    getAllPoints { [weak self] (points) in
        // you update you UI here, be sure to call in main thread when you are doing UI updates in closures.
        print(points)
    } apiError: { (error) in
        print(error)
    }
    
}

CodePudding user response:

It would be efficient if things are loosely coupled which can be done with Delegate pattern.

   protocol TempPointDelegate {
    func didUpdatePoints(_ tempPoints: [tempPoint])
    func didFailWithError(error: Error)
}

and in tempPoint Struct

    struct tempPoint: Decodable {
        let idPoint:Int
        let ptName:String
        let ptLat:Double
        let ptLong:Double
    }
    
    var delegate: TempPointDelegate?
    
    func getAllPoints(){
    
    if let url = URL(string: "[MyWebService.com]") {
            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data {
                    if let jsonString = String(data: data, encoding: .utf8) {
                        let jsonData = Data(jsonString.utf8)
                        do {
                            let points = try JSONDecoder().decode([tempPoint].self, from: jsonData)
                            self.delegate?.didUpdatePoints(points)
                            return
                        } catch let error {
                            self.delegate?.didFailWithError(error)
                            return
                        }
                    }
                }
            }.resume()
        }
    }
    

finally in your ViewController implement tempPointDelegate delegate

 class MainViewController: tempPointDelegate{
      override func viewDidLoad() {
             super.viewDidLoad()
             tempPoint.getAllPoints()
      }
     func didUpdatePoints(_ tempPoints: [tempPoint]) {
            DispatchQueue.main.async {
            //process the tempPoints here / call the func to handle tempPoints
            }
    }
    
    func didFailWithError(error: Error) {
        //process the error returned here.
    }
}

CodePudding user response:

First of all please name structs with starting uppercase letter (TempPoint).

Second of all the conversion to String and back to Data is pointless

In Swift 5.5 you can use async/await

enum URLError : Error { case badURL }

func getAllPoints() async throws -> [TempPoint] {

    guard let url = URL(string: "[MyWebService.com]") else { throw URLError.badURL }
    let (data, _) = try await URLSession.shared.data(from : url)
    return try JSONDecoder().decode([TempPoint].self, from: data)
}

And call it

Task {
    do {
       let points = try await getAllPoints()
    } catch {
        print(error)
    }
}
  • Related