Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
715 views
in Technique[技术] by (71.8m points)

alert - 为什么显示延迟警报?(Why the Delayed Alert Display?)

Scenario:

(场景:)
I'm playing around with accessing & displaying remote images to learn Combine's assorted notification flags/protocols.

(我正在玩访问和显示远程图像,以了解Combine的各种通知标记/协议。)

One Goal:

(一个目标:)
Accessing a bad URL should immediately display an Alert().

(访问错误的URL应该立即显示Alert()。)

Reality:

(现实:)
Alert is displayed AFTER then second request and beyond.

(警报显示然后第二请求和超越。)

在此处输入图片说明

Here's the main (calling) view:

(这是主(调用)视图:)

import Combine
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var settings: MySettings
    @State private var url: String = "https://garbage.com"  // ...purposely set to display alert.
    @State private var image: URLImage = URLImage()
    @State private var angelFish: Image = Image("QueenAngelfish")
    @State private var isPresented = false

    var body: some View {
        ZStack {
            Color.green
            NavigationView {
                VStack {
                    Button(action: {
                        self.url = "garbage.com"
                        self.isPresented = self.image.imageLoader.isPresented
                        self.image.imageLoader.load(url: URL(string: self.url)!)
                    }) {
                        Text("Get An Image")
                    }

                    angelFish
                        .resizable()
                        .frame(width: 300, height: 200, alignment: .center)
                        .padding()
                    image
                        .alert(isPresented: $isPresented, content: { () -> Alert in
                            Alert(title: Text(verbatim: "Unable to Acquire Image."))
                        })

                }.navigationBarTitle(Text(settings.name))
            }
        }
    }
}

Here's the access engine:

(这是访问引擎:)

import Combine
import SwiftUI

enum ImageURLError: Error {
    case dataIsNotAnImage
}

struct URLImage: View {
    @EnvironmentObject var settings: MySettings
    @ObservedObject var imageLoader: ImageLoader
    var placeholder: Image

    init() {
        self.placeholder = Image(systemName: "photo")
        self.imageLoader = ImageLoader()
    }

    var body: some View {
        VStack {
            imageLoader.image == nil ?
                placeholder : Image(uiImage: imageLoader.image!)
            Button(action: {
                self.settings.name = "Happy Thanks Giving"
                self.settings.isPresented = true
            }, label: {
                Text("Touch Me")
            })
        }
    }
}

// =====================================================================================================

class ImageLoader: ObservableObject {
    let id: String = UUID().uuidString
    var didChange = PassthroughSubject<Void, Never>()

    @Published var isPresented = false

    @Published var image: UIImage? {
        didSet {
            DispatchQueue.main.async {
                self.didChange.send()
            }
        }
    }

    // ---------------------------------------------------------------------------

    func load(url: URL) {
        print("Hello Ric: ", #function)

        URLSession.shared.dataTask(with: url) { data, _, error in
            DispatchQueue.main.async {
                if error != nil {
                    self.isPresented = true
                    self.didChange.send()   // ...attempting to activate alert().
                    return
                }

                self.image = UIImage(data: data!)
            }

        }.resume()
    }
}

This code purposely creates an error due to a bad URL.

(由于URL错误,此代码有意造成错误。)
I tried to immediately notify the calling routine via passing the boolean 'isPresented' flag as an '@Published' variable

(我试图通过将布尔值“ isPresented”标志作为“ @Published”变量传递来立即通知调用例程)

Expected Result:

(预期结果:)
Displayed Alert.

(显示的警报。)

Actual Result:

(实际结果:)
Alert is displayed AFTER & beyond the initial attempt.

(警报将在首次尝试之后显示。)

Question: How do I perform an INSTANT Alert display?

(问题:如何执行即时警报显示?)

  ask by Frederick C. Lee translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Ok, there were several issues here, mostly about ObservableObject usage and linking things together.

(好的,这里有几个问题,主要是关于ObservableObject用法以及将事物链接在一起的问题。)

Please find below modified module that works.

(请在下面找到有效的修改后模块。)

(I substituted some absent entities with mine just to test).

((我将一些不存在的实体替换为我的实体以进行测试)。)

import Combine
import SwiftUI

class ImageLoader: ObservableObject {
    let id: String = UUID().uuidString

    // !!! no need in didChange, @Published is already Publisher
    // see below .onReceive for usage example
    @Published var isPresented = false
    @Published var image: UIImage?

    func load(url: URL) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            DispatchQueue.main.async {
                if error != nil {
                    self.isPresented = true
                    return
                }
                self.image = UIImage(data: data!)
            }
        }.resume()
    }
}

class MySettings: ObservableObject { // << reconstructed for testing
    @Published var name = "My Name"
    @Published var isPresented = false
}

enum ImageURLError: Error {
    case dataIsNotAnImage
}

struct URLImage: View {
    @EnvironmentObject var settings: MySettings
    @ObservedObject var imageLoader: ImageLoader
    var placeholder: Image

    init() {
        self.placeholder = Image(systemName: "photo")
        self.imageLoader = ImageLoader()
    }

    var body: some View {
        VStack {
            imageLoader.image == nil ?
                placeholder : Image(uiImage: imageLoader.image!)
            Button(action: {
                self.settings.name = "Happy Thanks Giving"
                self.settings.isPresented = true
            }, label: {
                Text("Touch Me")
            })
        }
        .onReceive(imageLoader.$isPresented) { self.settings.isPresented = $0 }
    }
}

struct ContentView: View {
    @EnvironmentObject var settings: MySettings
    @State private var url: String = "https://garbage.com"  // << this url is valid
    @State private var image: URLImage = URLImage()
    @State private var angelFish: Image = Image("QueenAngelfish")

    var body: some View {
        ZStack {
            Color.green
            NavigationView {
                VStack {
                    Button(action: {
                        self.url = "garbage.com" // << this url is not valid [to test alert]
                        self.image.imageLoader.load(url: URL(string: self.url)!)
                    }) {
                        Text("Get An Image")
                    }

                    angelFish
                        .resizable()
                        .frame(width: 300, height: 200, alignment: .center)
                        .padding()
                    image
                        .alert(isPresented: $settings.isPresented) {
                            Alert(title: Text(verbatim: "Unable to Acquire Image."))
                        }
                }.navigationBarTitle(Text(settings.name))
            }
        }
    }
}

struct TestDelayedAlert_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(MySettings())
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...