首页 > 解决方案 > 将函数移出视图:在视图更新期间修改状态,这将导致未定义的行为

问题描述

我有一个选择器,让用户从他们的照片库中选择一张图片。这显示在一个工作表中,该工作表位于另一个工作表中,该工作表捕获用户数据并将其与核心数据一起保存。

当用户选择图像时,我会收到警告:

在视图更新期间修改状态,这将导致未定义的行为

我相信它源于修改状态的视图中的以下功能。

如何将此功能移出视图?

if (showCaptureImageView) {
    CaptureImageView(isShown: $showCaptureImageView, image: $image)
}

完整代码

import SwiftUI
import UIKit

struct CaptureImageView {
    @Binding var isShown: Bool
    @Binding var image: Image?
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(isShown: $isShown, image: $image)
    }
}

extension CaptureImageView: UIViewControllerRepresentable {
  func makeUIViewController(context: UIViewControllerRepresentableContext<CaptureImageView>) -> UIImagePickerController {
    let picker = UIImagePickerController()
    picker.delegate = context.coordinator
    return picker
  }
  
  func updateUIViewController(_ uiViewController: UIImagePickerController,
                              context: UIViewControllerRepresentableContext<CaptureImageView>) {
    
  }
}

struct addBookView: View {
    @Environment(\.managedObjectContext) var moc
    @Environment(\.presentationMode) var presentationMode
    
    @State private var title = ""
    @State private var author = ""
    @State private var currentPage = ""
    @State private var image: Image? = nil
    @State var showCaptureImageView: Bool = false
    
    var body: some View {
        NavigationView {
                Form {
                    Section {
                        TextField("What's the book title", text: $title)
                        TextField("Who's the author", text: $author)
                        TextField("What page are you on", text: $currentPage)
                    }
                    Section {
                        Button (action: {
                            self.showCaptureImageView.toggle()
                        }) {
                            Text("Take a picture")
                        }
                        .sheet(isPresented: $showCaptureImageView) {
                            CaptureImageView(isShown: self.$showCaptureImageView, image: self.$image)
                        }
                        image?.resizable()
                            .frame(width: 250, height: 250)
                            .clipShape(Circle())
                            .overlay(Circle().stroke(Color.white, lineWidth: 4))
                            .shadow(radius: 10)
                        if (showCaptureImageView) {
                          CaptureImageView(isShown: $showCaptureImageView, image: $image)
                        }
                    }
                    Section {
                        Button ("Save") {
                             let newBook = Book(context: self.moc)
                             newBook.title = self.title
                             newBook.author = self.author
                             newBook.currentPage = self.currentPage
                             
                             try? self.moc.save()
                             self.presentationMode.wrappedValue.dismiss()
                         }
                    }
                }
        }
        .navigationBarTitle("Add a book")
    }
}

struct addBookView_Previews: PreviewProvider {
    static var previews: some View {
        addBookView()
    }
}

协调员

import SwiftUI

class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    
    @Binding var isCoordinatorShown: Bool
    @Binding var imageInCoordinator: Image?
    
    init(isShown: Binding<Bool>, image: Binding<Image?>) {
        _isCoordinatorShown = isShown
        _imageInCoordinator = image
    }
    
    func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let unwrapImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
        imageInCoordinator = Image(uiImage: unwrapImage)
        isCoordinatorShown = false
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        isCoordinatorShown = false
    }
}

标签: iosswiftxcodecore-dataswiftui

解决方案


尝试在下一个事件循环中推迟图像更新(这是避免运行时错误的常用方法),例如

guard let unwrapImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }

DispatchQueue.main.async {
   imageInCoordinator = Image(uiImage: unwrapImage)
}
isCoordinatorShown = false

推荐阅读