使用按钮从 API 加载图像

Load image from API using a button

在我的应用中,用户可以从特定 API 中搜索图像,然后单击按钮获取该图像的 url。我的问题是如何向用户显示图像?

内容视图:

@StateObject var dataModel = DataModel()

 var body: some View {

       // Text to display the link of the Image, when clicked on, it opens in Safari:
        Text("\(dataModel.imageURL)")
            .padding()
            .onTapGesture {
                let url = URL(string: dataModel.imageURL)
                guard let recievedURL = url, UIApplication.shared.canOpenURL(recievedURL) else { return }
                UIApplication.shared.open(recievedURL)
            }

        // TextField where the user enters the search word:
        TextField("Search Images...", text: $dataModel.searchTerm)

        // After pressing this button, the DataModel fetches the data and presents the url in the text above:
        Button(action: {
            dataModel.fetchAPI()
        }, label: {
            Text("Fetch Image")
        })
    }

DataModel() 中获取数据的函数:


    @Published var imageURL = String()
    @Published var searchTerm = String()

func fetchAPI() {
        guard let url = URL(string:{The url including the searchWord}) else { return }
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let recievedData = data, error == nil else {
                print("ERROR: \(String(describing: error?.localizedDescription))")
                return
            }
            do {
                let model = try JSONDecoder().decode(ImageData.self, from: recievedData)
                DispatchQueue.main.async {
                    self.imageURL = model.data.first?.url ?? "No URL"
                }
            } catch {
                print("Error: \(error.localizedDescription)")
            }
        }
        .resume()
    }

当我尝试根据接收到的数据创建图像时,应用程序立即崩溃,因为数据为零。那么如何在用户按下按钮获取数据后显示图像?

获得 URL 后,您可以启动另一个网络调用以从 URL 获取数据。然后,您可以像这样从 Data 创建一个 UIImage

UIImage(data: receivedData)

如果你添加一个 UIImage 属性 到你的数据模型,你会得到这样的东西:

@Published var image : UIImage?

//after you get the data from your network call:
image = UIImage(data: receivedData)

然后,在您的 ContentView 中,您可以显示该图像(如果存在):

if let image = dataModel.image {
  Image(uiImage: image)
}

您的数据模型中的函数可能看起来像这样来实现此目的:

class DataModel : ObservableObject {

    //other published properties    

    @Published var image : UIImage?

    var cancellable : AnyCancellable?
    
    func getImageFromURL(url: URL) {
        self.cancellable =
            URLSession.shared.dataTaskPublisher(for: url)
            .receive(on: RunLoop.main)
            .sink(receiveCompletion: { (completion) in
                //handle errors
            }, receiveValue: { (output) in
                self.image = UIImage(data: output.data)
            })
    }

    //your original function to get the JSON and decode it...
}

注意:确保在文件顶部导入 Combine,否则 AnyCancellable 将不可用