为什么延迟警报显示?
Why the Delayed Alert Display?
场景:
我正在尝试访问和显示远程图像以了解 Combine 的各种通知 flags/protocols。
一个目标:
访问错误的 URL 应该 立即 显示 Alert()。
现实:
显示警报 AFTER 然后是第二个请求及以后。
这是主(调用)视图:
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 = [=10=] }
}
}
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())
}
}
场景:
我正在尝试访问和显示远程图像以了解 Combine 的各种通知 flags/protocols。
一个目标:
访问错误的 URL 应该 立即 显示 Alert()。
现实:
显示警报 AFTER 然后是第二个请求及以后。
这是主(调用)视图:
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 = [=10=] }
}
}
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())
}
}