SwiftUI what is the return-type of my own render's function?

can i define something like func myRender() -> Image | Text (union-types) ?

hi, all. i think i miss a unsolvable problem on my SwiftUI demo: a simple url image renderer with a sub-render piece, codes here:

import Foundation
import SwiftUI

struct URLImage: View {
    var urlString: String;
    @State var loaded = false
    @State var error: Any?
    @State var data: Data?

    func didMount() {
        print("!!! viewWillAppear", self.urlString)
        // just load url and get data in the callback fn:
        // (String, (Any?, Data) -> Void) -> Void
        // $0 is error, $1 is data
        loadImage(urlString: self.urlString) {
            print("loaded", $0 ?? "no error", $1)
            self.error = $0
            self.data = $1
            self.loaded = true
        }
    }
    
    // what is the return-type of tryRender ?
    func tryRender() -> View { // doesn't works now because `View` is a protocol
        // self.data maybe nil or with a wrong binary format
        guard let image = try? Image(nsImage: NSImage(data: self.data!)!) else {
//            return Image("image_format_error") // it works with "func tryRender() -> Image" but ... emmm
            return Text("image_format_error") // this is what i want, but this can't works
        }

        return image
    }

    var body: some View {
        self.didMount()
        return VStack {
            if (self.error != nil) {
                Text("URLImage Error")
            } else {
                if (self.loaded) {
                    self.tryRender()
                } else {
                    Text("not loaded")
                }
            }
        }
    }
}

struct URLImage_Previews: PreviewProvider {
    static var previews: some View {
        URLImage(
            urlString: "http://127.0.0.1:3000/0009.jpg"
        )
    }
}

the problem is the return type of tryRender(), i can’t write tryRender() -> Image | Text like typescript’s union types to express my opinion.

is Image or Text have a base type to make it works ? or there is another way to write such the sub-render pieces func ?

>Solution :

You can use @ViewBuilder and your return type should be some View

@ViewBuilder func tryRender() -> some View {
        if let image = try? Image(nsImage: NSImage(data: self.data!)!)  {
            image
        } else {
            Text("image_format_error")
        }
    }

Leave a Reply