0

I'm trying to call a function from view using SwiftUI. This view receive an String parameter from view that is calling it.

struct BookList: View {
    var name: String
    var body: some View {
        let data: () = getData(from: self.name)
        ...
    }
}

The function get data is consuming a rest service and getting some data.

func getData(from url: String){
    let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data, response, error in
        guard let data = data, error == nil else {
            print("Something went wrong")
            return
        }
        
        //Have data
        var result: Response?
        do {
            result = try JSONDecoder().decode(Response.self, from: data)
        } catch {
            print("failed to convert \(error.localizedDescription)")
        }
        
        guard let json = result else{
            return
        }
        
        print("Page: \(json.page)")
        print("Books: \(json.books.first)")
    })
    
    task.resume()
}

struct Response: Codable {
    var error: String
    var total: String
    var page: String
    var books: [MyBook]
}

The problem is that I don't know how to call this function when view start. In this sample I'm getting the error:

"Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type"

How can I fix it?

2 Answers 2

1

"Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type"

This specific error is because you have other statements besides Views in your body property. Typically, the body property will use an implicit return but if you include other statements—such as your call to getData—then you need to use an explicit return instead. Like so:

    var body: some View {
        let data: () = getData(from: self.name)
        return ...your View(s)
    }
Sign up to request clarification or add additional context in comments.

1 Comment

This is great, had to use this to run a function in a TimelineView whenever it triggers.
0

You need to return data from getData. Because it's asynchronous, you need a completion handler:

func getData(from url: String, completion: @escaping (Response) -> Void) {
    let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data, response, error in
        ...
        completion(json)
    })
    task.resume()
}

and call it in your view in .onAppear:

struct BookList: View {
    var name: String

    @State var data: Response?

    var body: some View {
        Text("Your view...")
            .onAppear {
                getData(from: self.name) { data in
                    DispatchQueue.main.async {
                        self.data = data
                    }
                }
            }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.