如何在 Swiftui 上将“ImagePickerView”类型的值转换为预期的参数类型“String”?

问题描述

我正在尝试构建一个应用程序,用户可以在其中插入电影名称,并且可以直接从照片库中将图像添加到应用程序中(使用 UIKit。值得庆幸的是,用户可以从中插入文本和图像的部分照片库有效。我的问题是将该数据从 .sheet 传输到列表。用户插入的 TextFields 中的信息工作正常并显示在列表中,但图像未显示。我不断收到错误消息“无法将‘ImagePickerView’类型的值转换为预期的参数类型‘String’”。我不知道如何解决这个问题。当我尝试插入图像时,这个问题出现在 ContentView.swift 文件中,在 MovieRow 结构中(). 任何帮助将不胜感激。提前致谢。 下面是我的 ContentView 文件

//  ContentView.swift
//  MovieListEditttt
//

import SwiftUI

struct ContentView: View {

@State var movieAdd: [MovieAdd] = []

@State private var newMovieName: String = ""
@State private var showNewMovie = false

@State private var newMovieImage = UIImage()

var body: some View {
    ZStack {
        vstack {
            HStack {
                Text("Movies Watched ratings")
                    .font(.system(size: 40,weight: .black,design: .rounded
                    ))
                
                Spacer()
                
                Button(action: {
                    self.showNewMovie = true
                }) {
                    Image(systemName: "plus.circle.fill")
                        .font(.largeTitle)
                        .foregroundColor(.yellow)
                }
            }
            
            List{
                ForEach(movieAdd) {movie in
                    movieRow(movieAdd: movie)
                }
            }
        }
        
        if showNewMovie {
            BlankView(bGColor: .black)
                .opacity(0.5)
                .onTapGesture {
                    self.showNewMovie = false
                }
            NewMovieView(isShow: $showNewMovie,addMovie: $movieAdd,newMovieName: newMovieName)
                .transition(.move(edge: .bottom))
                .animation(.interpolatingSpring(stiffness: 200.0,damping: 25.0,initialVeLocity: 10.0))
        }
    }
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}

struct movieRow: View {

@Observedobject var movieAdd : MovieAdd

var body: some View {
        vstack {
            
            Image(movieAdd.movieImage)
                .resizable()
                .frame(width: 100,height: 100)
            
            Text(movieAdd.movieName)
        }
}
}

struct BlankView: View {
var bGColor: Color

var body: some View {
    vstack {
        Spacer()
    }
    .frame(minWidth: 0,maxWidth: .infinity,minHeight: 0,maxHeight: .infinity)
    .background(bGColor)
    .edgesIgnoringSafeArea(.all)
}
}

这是我的 MovieAdd.swift 文件,我在其中初始化了将放入列表中的所有变量。

import Foundation

class MovieAdd: ObservableObject,Identifiable {
var id = UUID()
@Published var movieName = ""
@Published var isComplete : Bool = false
@Published var movieImage : ImagePickerView

init(movieName: String,isComplete: Bool = false,movieImage: ImagePickerView) {
    self.movieName = movieName
    self.isComplete = isComplete
    self.movieImage = movieImage
}
}

这是我的 NewMovieView.swift 文件用户可以在其中将他们的电影信息插入到 TextField 中,并从他们的照片库中插入图像。这里也是我使用 UIKit 的地方。

import SwiftUI

struct NewMovieView: View {

@Binding var isShow: Bool
@Binding var addMovie: [MovieAdd]

@State var newMovieName: String = ""

@State var isShowingImagePicker = false
@State var imageInBlackBox = UIImage()

var body: some View {
    ScrollView {
    vstack {
        vstack (alignment: .leading) {
            HStack {
                Text("Add a New Movie")
                    .font(.system(.title,design: .rounded))
                    .bold()
            }
            ZStack {
                vstack {
                HStack (alignment: .center){
                    
                    Spacer()
                    Image(uiImage: imageInBlackBox)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200,height: 200)
                        .border(Color.black,width: 3)
                        .clipped()
                    Spacer()
                }
                
                vstack {
                    Spacer()
                    Button(action: {
                        self.isShowingImagePicker.toggle()
                    },label: {
                        Text("Select Image")
                            .font(.system(size: 15))
                    })
                    .sheet(isPresented: $isShowingImagePicker,content: { ImagePickerView(isPresented: $isShowingImagePicker,selectedImage: $imageInBlackBox)})
                }
                }
            }
            
            Group {
            TextField("Enter the movie name",text: $newMovieName)
            .padding()
            .background(Color(.systemGray6))
            
            }
            
            Button(action: {
                if self.newMovieName.trimmingCharacters(in: .whitespaces) == "" {
                    return
                }
                
                if self.isShowingImagePicker {
                    return 
                }
                
                self.isShow = false
                self.addMovieTask(movieName: self.newMovieName,movieImage: ImagePickerView(isPresented: $isShowingImagePicker,selectedImage: $imageInBlackBox))
            }) {
                Text("Save")
                    .font(.system(.headline,design: .rounded))
                    .foregroundColor(.red)
            }
        }
    }
        .background(Color.white)
    }
}

private func addMovieTask(movieName: String,movieImage: ImagePickerView) {
    
    let task = MovieAdd(movieName: movieName,movieImage: movieImage)
    addMovie.append(task)
}
}

struct NewMovieView_Previews: PreviewProvider {
static var previews: some View {
    NewMovieView(isShow: .constant(true),addMovie: .constant([]),newMovieName: "",isShowingImagePicker: true)
}
}

struct ImagePickerView: UIViewControllerRepresentable {

@Binding var isPresented: Bool
@Binding var selectedImage: UIImage

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerView>) -> some UIViewController {
    let controller = UIImagePickerController()
    controller.delegate = context.coordinator
    return controller
}

func makeCoordinator() -> ImagePickerView.Coordinator {
    return Coordinator(parent: self)
}

class Coordinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
    
    let parent: ImagePickerView
    init(parent: ImagePickerView){
        self.parent = parent
    }
    
    func imagePickerController(_ picker: UIImagePickerController,didFinishPickingMediawithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let selectedImage = info[.originalImage] as? UIImage {
            print(selectedImage)
            self.parent.selectedImage = selectedImage
        }
        self.parent.isPresented = false
    }
}

func updateUIViewController(_ uiViewController: ImagePickerView.UIViewControllerType,context: UIViewControllerRepresentableContext<ImagePickerView>) {
    //
}
}

解决方法

更改 #1:

您的模型应该通常struct,除非有非常令人信服的理由将其设为ObservableObject。在这种情况下,struct 效果很好:

struct MovieAdd: Identifiable {
    var id = UUID()
    var movieName = ""
    var isComplete : Bool = false
    var movieImage : UIImage
}

请注意,我已将 movieImage 设为 UIImage

更改 #2:

Image(uiImage:) 中使用 MovieRowMovieAdd 属性不再需要 @ObservableObject,因为它只是一个 struct

另请注意,Swift 中的类型应大写以遵循约定)。

struct MovieRow: View {
    
    var movieAdd : MovieAdd
    
    var body: some View {
        VStack {
            
            Image(uiImage: movieAdd.movieImage)
                .resizable()
                .frame(width: 100,height: 100)
            
            Text(movieAdd.movieName)
        }
    }
}

完整代码,以防我忘记提及任何其他更改:


struct ContentView: View {
    
    @State var movieAdd: [MovieAdd] = []
    
    @State private var newMovieName: String = ""
    @State private var showNewMovie = false
    
    @State private var newMovieImage = UIImage()
    
    var body: some View {
        ZStack {
            VStack {
                HStack {
                    Text("Movies Watched Ratings")
                        .font(.system(size: 40,weight: .black,design: .rounded
                        ))
                    
                    Spacer()
                    
                    Button(action: {
                        self.showNewMovie = true
                    }) {
                        Image(systemName: "plus.circle.fill")
                            .font(.largeTitle)
                            .foregroundColor(.yellow)
                    }
                }
                
                List{
                    ForEach(movieAdd) {movie in
                        MovieRow(movieAdd: movie)
                    }
                }
            }
            
            if showNewMovie {
                BlankView(bGColor: .black)
                    .opacity(0.5)
                    .onTapGesture {
                        self.showNewMovie = false
                    }
                NewMovieView(isShow: $showNewMovie,addMovie: $movieAdd,newMovieName: newMovieName)
                    .transition(.move(edge: .bottom))
                    .animation(.interpolatingSpring(stiffness: 200.0,damping: 25.0,initialVelocity: 10.0))
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct MovieRow: View {
    
    var movieAdd : MovieAdd
    
    var body: some View {
        VStack {
            
            Image(uiImage: movieAdd.movieImage)
                .resizable()
                .frame(width: 100,height: 100)
            
            Text(movieAdd.movieName)
        }
    }
}

struct BlankView: View {
    var bGColor: Color
    
    var body: some View {
        VStack {
            Spacer()
        }
        .frame(minWidth: 0,maxWidth: .infinity,minHeight: 0,maxHeight: .infinity)
        .background(bGColor)
        .edgesIgnoringSafeArea(.all)
    }
}

struct MovieAdd: Identifiable {
    var id = UUID()
    var movieName = ""
    var isComplete : Bool = false
    var movieImage : UIImage
}


struct NewMovieView: View {
    
    @Binding var isShow: Bool
    @Binding var addMovie: [MovieAdd]
    
    @State var newMovieName: String = ""
    
    @State var isShowingImagePicker = false
    @State var imageInBlackBox = UIImage()
    
    var body: some View {
        ScrollView {
            VStack {
                VStack (alignment: .leading) {
                    HStack {
                        Text("Add a New Movie")
                            .font(.system(.title,design: .rounded))
                            .bold()
                    }
                    ZStack {
                        VStack {
                            HStack (alignment: .center){
                                
                                Spacer()
                                Image(uiImage: imageInBlackBox)
                                    .resizable()
                                    .scaledToFill()
                                    .frame(width: 200,height: 200)
                                    .border(Color.black,width: 3)
                                    .clipped()
                                Spacer()
                            }
                            
                            VStack {
                                Spacer()
                                Button(action: {
                                    self.isShowingImagePicker.toggle()
                                },label: {
                                    Text("Select Image")
                                        .font(.system(size: 15))
                                })
                                .sheet(isPresented: $isShowingImagePicker,content: { ImagePickerView(isPresented: $isShowingImagePicker,selectedImage: $imageInBlackBox)})
                            }
                        }
                    }
                    
                    Group {
                        TextField("Enter the movie name",text: $newMovieName)
                            .padding()
                            .background(Color(.systemGray6))
                        
                    }
                    
                    Button(action: {
                        if self.newMovieName.trimmingCharacters(in: .whitespaces) == "" {
                            return
                        }
                        
                        if self.isShowingImagePicker {
                            return
                        }
                        
                        self.isShow = false
                        self.addMovieTask(movieName: self.newMovieName,movieImage: ImagePickerView(isPresented: $isShowingImagePicker,selectedImage: $imageInBlackBox))
                    }) {
                        Text("Save")
                            .font(.system(.headline,design: .rounded))
                            .foregroundColor(.red)
                    }
                }
            }
            .background(Color.white)
        }
    }
    
    private func addMovieTask(movieName: String,isComplete: Bool = false,movieImage: ImagePickerView) {
        
        let task = MovieAdd(movieName: movieName,movieImage: movieImage.selectedImage)
        addMovie.append(task)
    }
}

struct NewMovieView_Previews: PreviewProvider {
    static var previews: some View {
        NewMovieView(isShow: .constant(true),addMovie: .constant([]),newMovieName: "",isShowingImagePicker: true)
    }
}

struct ImagePickerView: UIViewControllerRepresentable {
    
    @Binding var isPresented: Bool
    @Binding var selectedImage: UIImage
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerView>) -> some UIViewController {
        let controller = UIImagePickerController()
        controller.delegate = context.coordinator
        return controller
    }
    
    func makeCoordinator() -> ImagePickerView.Coordinator {
        return Coordinator(parent: self)
    }
    
    class Coordinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
        
        let parent: ImagePickerView
        init(parent: ImagePickerView){
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController,didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let selectedImage = info[.originalImage] as? UIImage {
                print(selectedImage)
                self.parent.selectedImage = selectedImage
            }
            self.parent.isPresented = false
        }
    }
    
    func updateUIViewController(_ uiViewController: ImagePickerView.UIViewControllerType,context: UIViewControllerRepresentableContext<ImagePickerView>) {
        //
    }
}