Попытка передать URL в загрузчик изображений в SwiftUI дает мне ноль - PullRequest
0 голосов
/ 07 ноября 2019

Итак, я пытаюсь заполнить список данными (в данном случае это книги) из JSON, JSON содержит изображения для каждой книги, которые я спрашивал, и Image Loader, предположительно, является единственным способомсделайте это.

Итак, позвольте мне показать вам некоторый код.

Это загрузчик изображений:

struct ImageView: View {
    @ObservedObject var imageLoader:ImageLoader
    @State var image:UIImage = UIImage()

    func imageFromData(_ data:Data) -> UIImage {
        UIImage(data: data) ?? UIImage()
    }

    init(withURL url:String) {
        imageLoader = ImageLoader(urlString:url)
    }

    var body: some View {
        VStack {

            Image(uiImage: imageLoader.data != nil ? UIImage(data:imageLoader.data!)! : UIImage())
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width:100, height:100)
        }
    }

}

class ImageLoader: ObservableObject {
    @Published var dataIsValid = false
    var data:Data?

    init(urlString:String) {
        guard let url = URL(string: urlString) else { return }
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
            DispatchQueue.main.async {
                self.dataIsValid = true
                self.data = data
            }
        }
        task.resume()
    }
}

Посмотрите на первую строку в VStackв body: some View из struct, вот где он падает и дает мне Unexpectedly found nil while unwrapping an Optional value.

Теперь это код для List:

let apiUrl = "https://qodyhvpf8b.execute-api.us-east-1.amazonaws.com/test/books"

class BooksViewModel: ObservableObject {
    @Published var books: [Book] = [
        .init(id: 1, nombre: "Libro 1", autor: "Autor 1", disponibilidad: true, popularidad: 100, imagen: "https://www.google.com.ar"),
        .init(id: 2, nombre: "Libro 2", autor: "Autor 2", disponibilidad: false, popularidad: 80, imagen: "https://www.google.com.ar"),
        .init(id: 3, nombre: "Libro 3", autor: "Autor 3", disponibilidad: true, popularidad: 60, imagen: "https://www.google.com.ar")
    ]

    func fetchBooks() {
        guard let url = URL(string: apiUrl) else { return }
        URLSession.shared.dataTask(with: url) { (data, resp, err) in
            DispatchQueue.main.async {
                do {
                    self.books = try JSONDecoder().decode([Book].self, from: data!)
                } catch {
                    print("Failed to decode JSON: ", error)
                }
            }
        }.resume()
    }
}

struct ContentView: View {

    @ObservedObject var booksVM = BooksViewModel()

    var body: some View {
        NavigationView {
            List {
                VStack(alignment: .leading) {
                    ForEach(booksVM.books.sorted { $0.popularidad > $1.popularidad}) { book in
                        HStack {
                            ImageView(withURL: book.imagen)
                            Text(book.nombre)
                            Spacer()
                            Text(String(book.popularidad))
                        }
                        HStack {
                            Text(book.autor)
                            Spacer()
                            if book.disponibilidad {
                                Text("Disponible")
                            } else {
                                Text("No disponible")
                            }
                        }
                        Spacer()
                    }
                }.padding([.leading, .trailing], 5)
            }
            .navigationBarTitle("Bienvenido a la librería flux")
            .onAppear(perform: self.booksVM.fetchBooks)
        }

    }
}

Первая строкаиз HStack, ImageView(withURL: book.imagen) это строка, которая предположительно передает строку для URL, но я не знаю почему, этого не происходит. book.imagen должен вернуть строку. Я не знаю, потому что это не возвращает строку или что-то не так в Image Loader. Не могу понять это. Остальные данные поступают просто отлично.

Вот фрагмент JSON:

[
    {
        "id": 1,
        "nombre": "The design of every day things",
        "autor": "Don Norman",
        "disponibilidad": true,
        "popularidad": 70,
        "imagen": "https://images-na.ssl-images-amazon.com/images/I/410RTQezHYL._SX326_BO1,204,203,200_.jpg"
    },
    {
        "id": 2,
        "nombre": "100 años de soledad",
        "autor": "Garcia Marquez",
        "disponibilidad": false,
        "popularidad": 43,
        "imagen": "https://images-na.ssl-images-amazon.com/images/I/51egIZUl88L._SX336_BO1,204,203,200_.jpg"
    },
    {
        "id": 3,
        "nombre": "El nombre del viento",
        "autor": "Patrik Rufus",
        "disponibilidad": false,
        "popularidad": 80,
        "imagen": "https://static.megustaleer.com/images/libros_200_x/EL352799.jpg"
    }
]

Если это поможет, это то, чего я пытаюсь достичь

Пожалуйста, дайте мне знать, если понадобятся дополнительные разъяснения.

1 Ответ

0 голосов
/ 07 ноября 2019

Нет ничего плохого в коде swiftUI. Вот пример кода рабочей модели. Может быть, вы что-то упустили в своей модели.

             struct Book: Identifiable, Decodable {
            var popularidad: Int = 0
            var imagen : String = ""
            var nombre : String = ""
            var autor : String = ""
            var disponibilidad : Bool = false
            var id : Int = 0
        }


        class  BooksViewModel: ObservableObject {
            @Published var books : [Book] = []
            func fetchBooks(){
                do{
                    if let url = Bundle.main.url(forResource: "LocalCache", withExtension: "json"){
                        if  let string = try String(contentsOf: url).data(using: .utf8){
                            self.books =  try JSONDecoder().decode([Book].self, from: string)}
                    }
                }
                catch{}
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...