如何使用SwiftUI重写同步方法?

huangapple go评论62阅读模式
英文:

How to rewrite sync method using SwiftUI?

问题

现在我正在使用UIImage同步扩展。

struct PostView: View {
    let url: String
    
    var body: some View {        
        PrivateImageView(image: UIImage(url:url))
     }
}
extension UIImage {
    public convenience init(url: String) {
        let url = URL(string: url)
        do {
            let data = try Data(contentsOf: url!)
            self.init(data: data)!
            return
        } catch let err {
            print("Error : \(err.localizedDescription)")
        }
        self.init()
    }
}

当我发布一张图片时,我收到了错误消息 Synchronous URL loading of http://local.host/images/123.jpeg should not occur on this application's main thread as it may lead to UI unresponsiveness. Please switch to an asynchronous networking API such as URLSession.,出现在 try Data(contentsOf: url!)

在PostView中,我使用了 PrivateImageView

要使用这个视图,我必须像这样指定参数 PrivateImageView(image: UIImage(xxxxxxxxx))

我的意思是,我必须使用 UIImage() 而不是 AsyncImage

我不知道如何修改 convenience init 来适应 PrivateImageView

请告诉我如何在这个上下文中使用异步函数。

英文:

Now I'm using UIImage sync extension.

struct PostView: View {
    let url: String
    
    var body: some View {        
        PrivateImageView(image: UIImage(url:url))
     }
}
extension UIImage {
    public convenience init(url: String) {
        let url = URL(string: url)
        do {
            let data = try Data(contentsOf: url!)
            self.init(data: data)!
            return
        } catch let err {
            print("Error : \(err.localizedDescription)")
        }
        self.init()
    }
}

When I post a image, I got the error Synchronous URL loading of http://local.host/images/123.jpeg should not occur on this application's main thread as it may lead to UI unresponsiveness. Please switch to an asynchronous networking API such as URLSession. at try Data(contentsOf: url!).

In PostView I use PrivateImageView.

To use the view I have to designate the argument like this PrivateImageView(image: UIImage(xxxxxxxxx)).

I mean I have to use UIImage() not AsyncImage.

I don't know how to change convenience init to adjust to PrivateImageView.

Please tell me how to use an async function in this context.

答案1

得分: 1

以下是您要翻译的内容:

无法同步从互联网/内网获取数据,您必须使用异步方法并考虑下载所需的时间。

extension String {
    public func getUIImage() async throws -> UIImage {
        guard let url = URL(string: self) else {
            throw URLError(.badURL)
        }
        
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }
        
        guard httpResponse.statusCode == 200 else {
            throw URLError(URLError.Code(rawValue: httpResponse.statusCode))
        }
        
        guard let image = UIImage(data: data) else {
            throw URLError(.fileDoesNotExist)
        }
        return image
    }
}

extension UIImage {
    static public func fromURL(url: String) async throws -> UIImage {
        let image = try await url.getUIImage()
        return image
    }
}

您可以将`PostView`重写为类似以下内容的形式。

struct PostView: View {
    let url: String
    @State private var uiImage: UIImage?
    var body: some View {
        Group{
            if let uiImage {
                PrivateImageView(image: uiImage)
            } else {
                ProgressView() // 下载时显示此内容
                    .task {
                        do {
                            self.uiImage = try await url.getUIImage()
                            // 或
                            // self.uiImage = try await UIImage.fromURL(url: url)
                        } catch {
                            print(error)
                        }
                    }
            }
        }
    }
}
英文:

There is no way to get a data from the inter/intranet synchronously you have to use an async method and account for the time it takes to download.

extension String {
    public func getUIImage() async throws -> UIImage {
        guard let url = URL(string: self) else {
            throw URLError(.badURL)
        }
        
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }
        
        guard httpResponse.statusCode == 200 else {
            throw URLError(URLError.Code(rawValue: httpResponse.statusCode))
        }
        
        guard let image = UIImage(data: data) else {
            throw URLError(.fileDoesNotExist)
        }
        return image
    }
}

extension UIImage {
    static public func fromURL(url: String) async throws -> UIImage {
        let image = try await url.getUIImage()
        return image
    }
}

You can rewrite PostView to something like.

struct PostView: View {
    let url: String
    @State private var uiImage: UIImage?
    var body: some View {
        Group{
            if let uiImage {
                PrivateImageView(image: uiImage)
            } else {
                ProgressView() //Show this while downloading
                    .task {
                        do {
                            self.uiImage = try await url.getUIImage()
                            // or
                            // self.uiImage = try await UIImage.fromURL(url: url)
                        } catch {
                            print(error)
                        }
                    }
            }
        }
    }
}

huangapple
  • 本文由 发表于 2023年6月1日 19:54:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76381598.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定