SwiftUI视图中if语句内函数调用无法终止问题求助
问题分析与解决方案
你的问题出在直接在View的body中执行imageAdd函数——SwiftUI的body会在任何状态/观察对象变化时重新计算,当你调用imageAdd修改imgArray(ObservedObject)时,会触发body再次刷新;即使你把image设为nil,ObservedObject的变化还是会让body重新执行,进而再次进入判断逻辑,导致无限循环。
另外你提到在imagePickerController里调用imageAdd无效,是因为ImagePickerView内部自己初始化了imgArray和imgAdded,这是全新的实例,和bottomButtons里的共享实例不是同一个,所以修改不会同步。
修复步骤
- 移除body中的判断逻辑,改用
.onChange(of: image)监听图片选中事件,仅在图片被设置时执行一次imageAdd。 - 让
ImagePickerView不再持有独立的imgArray和imgAdded实例,只负责传递选中的图片到外部的image绑定变量。
修正后的完整代码
struct bottomButtons: View { @State private var showImagePicker = false @State var image: UIImage? @State private var newImageChosen = false @ObservedObject var imgArray = imagesArray() @ObservedObject var imgAdded = imageAdded() var body: some View { HStack { // 相册选择按钮 Button(action: { self.showImagePicker = true }, label: { Image(systemName: "photo") }) .sheet(isPresented: $showImagePicker) { ImagePickerView(image: self.$image, showImagePicker: self.$showImagePicker, newImageChosen: self.$newImageChosen) } .scaleEffect(3.5) .tint(.black) .offset(x: -80) .padding() Button(action: { }, label: { Image(systemName: "camera.aperture") }) .scaleEffect(4) .tint(.black) .padding() Button(action: { }, label: { Image(systemName: "arrowshape.right") }) .scaleEffect(3.5) .tint(.black) .offset(x: 80) .padding() } .offset(y: 335) .frame(maxWidth: .infinity) // 监听image的变化,仅当image不为nil时执行添加逻辑 .onChange(of: image) { newImage in guard let tempImage = newImage else { return } imageAdd(imgSource: tempImage, imgArray: imgArray, imgAdded: imgAdded) image = nil // 清空image,避免重复触发 } } } struct ImagePickerView: UIViewControllerRepresentable { @Binding var image: UIImage? @Binding var showImagePicker: Bool @Binding var newImageChosen: Bool // 移除内部的imgArray和imgAdded实例,不需要在这里持有 func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> UIImagePickerController { let imagePicker = UIImagePickerController() imagePicker.sourceType = .photoLibrary imagePicker.delegate = context.coordinator return imagePicker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) { // 无需更新 } class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { let parent: ImagePickerView init(_ parent: ImagePickerView) { self.parent = parent } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { parent.image = image parent.newImageChosen = true // 可选:标记图片已选中 } parent.showImagePicker = false } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { parent.showImagePicker = false } } } func imageAdd(imgSource: UIImage, imgArray: imagesArray, imgAdded: imageAdded) { imgAdded.imgAdded = true imgArray.images.append(editableImg(id: imgArray.images.count, imgSrc: imgSource, size: [50, 80], scalar: 1.0)) imgAdded.addIndex = imgArray.images.endIndex - 1 imgAdded.imgAdded = false print("Image Added") } // 补充你用到的ObservedObject定义(方便参考) class imagesArray: ObservableObject { @Published var images: [editableImg] = [] } class imageAdded: ObservableObject { @Published var imgAdded: Bool = false @Published var addIndex: Int = 0 } struct editableImg: Identifiable { let id: Int let imgSrc: UIImage let size: [CGFloat] let scalar: Double }
关键说明
- 使用
.onChange(of: image)可以精准监听image变量的变化,只有当image被设置为新值(用户选中图片)时才执行一次添加逻辑,避免了body重绘导致的无限循环。 ImagePickerView只负责传递选中的图片到外部的绑定变量,不再持有独立的imgArray实例,确保修改的是共享的数据源。- 执行完
imageAdd后将image设为nil,避免后续如果image再次被意外设置时重复触发逻辑。
内容的提问来源于stack exchange,提问作者Refactorizer
相关产品推荐
相关产品推荐

