Now, when the application is opened, the image from the link is displayed, but if the user does not have the Internet, then the image from the files of my application is displayed
how instead of my image - name: "noconnection", show my structure: Indicator() if the user has no internet connection.
my code:
struct RemoteImage: View {
private enum LoadState {
case loading, success, failure
}
private class Loader: ObservableObject {
var data = Data()
var state = LoadState.loading
init(url: String) {
guard let parsedURL = URL(string: url) else {
fatalError("Invalid URL: \(url)")
}
URLSession.shared.dataTask(with: parsedURL) { data, response, error in
if let data = data, data.count > 0 {
self.data = data
self.state = .success
} else {
self.state = .failure
}
DispatchQueue.main.async {
self.objectWillChange.send()
}
}.resume()
}
}
@StateObject private var loader: Loader
var loading: Image
var failure: Image
var body: some View {
selectImage()
.resizable()
}
init(url: String, loading: Image = Image("loadingimage"), failure: Image = Image("noconnection")) {
_loader = StateObject(wrappedValue: Loader(url: url))
self.loading = loading
self.failure = failure
}
private func selectImage() -> Image {
switch loader.state {
case .loading:
return loading
case .failure:
return failure
default:
if let image = UIImage(data: loader.data) {
return Image(uiImage: image).resizable()
} else {
return failure
}
}
}
}
my structure - Indicator() - code
struct Indicator : UIViewRepresentable {
func makeUIView(context: Context) -> UIActivityIndicatorView {
let indicator = UIActivityIndicatorView()
indicator.startAnimating()
indicator.style = .large
indicator.color = .systemTeal
return indicator
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
//
}
}
This structure - Indicator() - should be shown instead of an image "noconnection"
I will be grateful for any help
CodePudding user response:
You could change your failure
type to accept an Indicator
. Then, change your selectImage
to a @ViewBuilder
that returns some View
:
struct RemoteImage: View {
private enum LoadState {
case loading, success, failure
}
private class Loader: ObservableObject {
var data = Data()
var state = LoadState.loading
init(url: String) {
guard let parsedURL = URL(string: url) else {
fatalError("Invalid URL: \(url)")
}
URLSession.shared.dataTask(with: parsedURL) { data, response, error in
if let data = data, data.count > 0 {
self.data = data
self.state = .success
} else {
self.state = .failure
}
DispatchQueue.main.async {
self.objectWillChange.send()
}
}.resume()
}
}
@StateObject private var loader: Loader
var loading: Image
var failure: Indicator
var body: some View {
selectImage()
}
init(url: String, loading: Image = Image("loadingimage").resizable(), failure: Indicator = Indicator()) {
_loader = StateObject(wrappedValue: Loader(url: url))
self.loading = loading
self.failure = failure
}
@ViewBuilder private func selectImage() -> some View {
switch loader.state {
case .loading:
loading
case .failure:
failure
default:
if let image = UIImage(data: loader.data) {
Image(uiImage: image).resizable()
} else {
failure
}
}
}
}
In this case, you might want to get rid of the default argument and just set var failure = Indicator()
instead of using the initializer