Tuesday, February 27, 2024

Learning Swift pt 1. (of who knows how many posts)

 I came across some old code I had in a project and I can't understand what is happening:

        var str = "blah"

        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

            print(response)

            var err: NSError?

            do {

                let myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) //as [[String:Any]]

                print(myJson)

                str = String(describing: myJson)


                Task {

                    await MainActor.run {() -> Void in

                        self.m_textView.string = str

                    }}

                

            } catch let error as NSError {

                err = error

            }

        }.resume()


So how to parse this? Because at the end of the block we see the resume() being called. Does the resume() return a Task object? No. I just remembered that a block at the end is actually passed as the last parameter to the function being called (dataTask()). So what returns a task object is the call to dataTask() not the call to resume(). This syntactic sugar can be confusing!


But on second thought resume() is only called on a Task() object right? So is the .resume() actually being called on the result of "let task ="? Ugh.

This is one of the reasons I hate swift. What code does is not obvious.

Ok, I found some sample code on Apple's site which is clearer:

func startLoad() {

    let url = URL(string: "https://www.example.com/")!

    let task = URLSession.shared.dataTask(with: url) { data, response, error in

        if let error = error {

            self.handleClientError(error)

            return

        }

        guard let httpResponse = response as? HTTPURLResponse,

            (200...299).contains(httpResponse.statusCode) else {

            self.handleServerError(response)

            return

        }

        if let mimeType = httpResponse.mimeType, mimeType == "text/html",

            let data = data,

            let string = String(data: data, encoding: .utf8) {

            DispatchQueue.main.async {

                self.webView.loadHTMLString(string, baseURL: url)

            }

        }

    }

    task.resume()

}


Here you see that resume is actually being called on the task. Ugh.

Update: Mystery solved! That first piece of code is wrong. The calculated type of task would be void because resume() returns void. I copy-pasted that code from somewhere and that somewhere has bad code. Ugh.

No comments:

Post a Comment