alert - 为什么显示延迟警报?
问题描述
场景:
我正在尝试访问和显示远程图像以了解 Combine 的各种通知标志/协议。
一个目标:
访问错误的 URL 应立即显示 Alert()。
现实:
警报显示在第二个请求之后及之后。
这是主要(调用)视图:
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))
}
}
}
}
这是访问引擎:
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()
}
}
由于 URL 错误,此代码故意创建错误。
我试图通过将布尔“isPresented”标志作为“@Published”变量传递来立即通知调用例程
预期结果:
显示警报。
实际结果:
在初始尝试之后及之后显示警报。
问题:如何执行即时警报显示?
解决方案
好的,这里有几个问题,主要是关于 ObservableObject 的使用和将事物链接在一起。请在下面找到有效的修改模块。(我用我的替换了一些不存在的实体只是为了测试)。
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())
}
}
推荐阅读
- python - Zybooks Python 活动 1.10.1
- flutter - Android Studio 中的 Flutter 项目数据库检查器北极狐
- gitlab - 如何在 Bitnami Gitlab CE 上启用包注册表
- mysql - SQL将行作为列
- javascript - 如何按名称对数组进行排序?
- python - 将值移动到另一列的第一个值所在的行
- ios - 从 RxTableViewSectionedReloadDataSource 调用 self 不起作用
- c - 传递 (void*) 100 作为参数
- html - 如何使用html标签显示明文的html效果
- html - 整行的卡片/盒子尺寸相同,具体取决于最大的卡片