将内容模型转换为 EnvironmentObject [英] Convert Contentful Model to EnvironmentObject

查看:25
本文介绍了将内容模型转换为 EnvironmentObject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将我的 Contentful 模型转换为可在多个视图之间访问.

I need to convert my Contentful model to be accessible between multiple views.

因此,例如,我将有一个电影列表和每个将有一个图像,标题和;预告片的 URL.我将有一个处理图像的视图,当用户点击图像时,我希望标题的视图更新 &将根据选择播放要更新的预告片的视图.

So, for example, I will have a list of movies & each will have an image, title & a URL to a trailer. I will have a view for handling the images and when a user taps on an image I would like the view for the title to update & the view that will play the trailer to update based on the selection.

下面更新的最佳方式是什么,以便当我调用 selectableRow 时,我可以更新我的标题 &我的视频播放器有正确的数据?

What would be the best way to update below so that when I call selectableRow I can update my title & my video player with the correct data?

我已经尝试将我的 Movie 结构更新为一个类并使其成为 ObservableObject 但这只会导致错误.

I've tried updating my Movie struct to a class and making it ObservableObject but that just leads to errors.

import SwiftUI
import Combine
import Contentful

struct Movie: Codable, Identifiable, FieldKeysQueryable, EntryDecodable {

    static let contentTypeId: String = "movies"

    // FlatResource Memberes.
    let id: String
    var updatedAt: Date?
    var createdAt: Date?
    var localeCode: String?

    var title: String
    var movieId: String
    var movieTrailer: String

    enum FieldKeys: String, CodingKey {

        case title, movieId, movieTrailer
    }

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case title = "title"
        case movieId = "movieId"
        case movieTrailer = "movieTrailer"
    }
}

public class MovieFetcher: ObservableObject {

    @Published var movies = [Movie]()

    init() {
        getArray(id: "movies") { (items) in
            items.forEach { (item) in
                self.movies.append(Movie(id: item.id, title: item.title, movieId: item.movieId, movieTrailer: item.movieTrailer))
            }
        }
    }

    func getArray(id: String, completion: @escaping([Movie]) -> ()) {

        let client = Client(spaceId: spaceId, accessToken: accessToken, contentTypeClasses: [Movie.self])

        let query = QueryOn<Movie>.where(contentTypeId: "movies")

        client.fetchArray(of: Movie.self, matching: query) { (result: Result<ArrayResponse<Movie>>) in
            switch result {
            case .success(let array):
                DispatchQueue.main.async {
                    completion(array.items)
                }
            case .error(let error):
                print(error)
            }
        }
    }
}

struct moviesView : View {

    @ObservedObject var fetcher = MovieFetcher()

    @State var selectMovie: Movie? = nil

    @Binding var show: Bool

    var body: some View {
        HStack(alignment: .bottom) {
            if show {
                ScrollView(.horizontal) {
                    Spacer()

                    HStack(alignment: .bottom, spacing: 30) {
                        ForEach(fetcher.movies, id: \.self) { item in
                            selectableRow(movie: item, selectMovie: self.$selectMovie)
                        }
                    }
                    .frame(minWidth: 0, maxWidth: .infinity)
                }
                .padding(.leading, 46)
                .padding(.bottom, 26)
            }
        }
    }
}

struct selectableRow : View {

    var movie: Movie

    @Binding var selectedMovie: Movie?

    @State var initialImage = UIImage()

    var body: some View {
        ZStack(alignment: .center) {
            if movie == selectedMovie {
                Image("")
                .resizable()
                .frame(width: 187, height: 254)
                .overlay(
                    RoundedRectangle(cornerRadius: 13)
                Image(uiImage: initialImage)
                .resizable()
                .cornerRadius(13.0)
                .frame(width: 182, height: 249)
                .onAppear {
                    let urlString = "\(urlBase)\(self.movie.movieId).png?"
                    guard let url = URL(string: self.urlString) else { return }
                    URLSession.shared.dataTask(with: url) { (data, response, error) in
                        guard let data = data else { return }
                        guard let image = UIImage(data: data) else { return }

                        RunLoop.main.perform {
                            self.initialImage = image
                        }

                    }.resume()
                }
            } else {
                Image(uiImage: initialImage)
                .resizable()
                .cornerRadius(13.0)
                .frame(width: 135, height: 179)
                .onAppear {
                   let urlString = "\(urlBase)\(self.movie.movieId).png?"
                   guard let url = URL(string: self.urlString) else { return }
                    URLSession.shared.dataTask(with: url) { (data, response, error) in
                        guard let data = data else { return }
                        guard let image = UIImage(data: data) else { return }

                        RunLoop.main.perform {
                            self.initialImage = image
                        }

                    }.resume()
                }
            }
        }
        .onTapGesture {
            self.selectedMovie = self.movie
        }
    }
}

struct mainView : View {

    @ObservedObject var fetcher = MovieFetcher()

    @State private var show = true

    var body: some View {
        ZStack {
            trailerView(show: $show)
            titleView(show: $show)
            moviesView(show: $show)
        }
    }
}

class hostingController: UIHostingController<mainView> {

    required init?(coder: NSCoder) {
        super.init(coder: coder,rootView: mainView().environmentObject(Movie())); // Getting error here
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

推荐答案

我假设您想在 UIKit 项目中使用 mainView.

I'm assuming you want to use the mainView in a UIKit project.

不确定您要做什么,但您不能这样做:

Not sure what you are trying to do, but you can't do this:

required init?(coder: NSCoder) {
        super.init(coder: coder,rootView: mainView().environmentObject(Movie())); // Getting error here
    }

由于您已经有了一个可观察对象 (MovieFetcher),您可以在 mainView 或任何其他视图中使用 fetcher.movi​​es 访问电影.

Since you already have an observable object (MovieFetcher), you can access the movies using fetcher.movies in the mainView or any other view.

这篇关于将内容模型转换为 EnvironmentObject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆