0

我想将手机照片库中的图像添加到我制作的拼贴布局中。首先,我在 SwiftUI 中将拼贴布局设置为一个名为 CollageLayoutOne 的单独视图。

import SwiftUI

struct CollageLayoutOne: View {
    
    var uiImageOne: UIImage
    var uiImageTwo: UIImage
    var uiImageThree: UIImage
    
    var body: some View {
        
        Rectangle()
            .fill(Color.gray)
            .aspectRatio(1.0, contentMode: .fit)
            .overlay {
                HStack {
                    Rectangle()
                        .fill(Color.gray)
                        .overlay {
                            Image(uiImage: uiImageOne)
                                .resizable()
                                .aspectRatio(contentMode: .fill)
                        }
                        .clipped()
                    VStack {
                        Rectangle()
                            .fill(Color.gray)
                            .overlay {
                                Image(uiImage: uiImageTwo)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                            }
                            .clipped()
                        Rectangle()
                            .fill(Color.gray)
                            .overlay {
                                Image(uiImage: uiImageThree)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                            }
                            .clipped()
                    }
                }
                .padding()
            }
    }
}

然后我有一个单独的视图 (PageView),我想在其中显示 CollageLayoutOne 视图,它还托管用于访问图像库的按钮。

struct PageView: View {
    
    @State private var photoPickerIsPresented = false
    @State var pickerResult: [UIImage] = []
    
    var body: some View {
      NavigationView {
        ScrollView {
            if pickerResult.isEmpty {
                
            } else {
                CollageLayoutOne(uiImageOne: pickerResult[0], uiImageTwo: pickerResult[1], uiImageThree: pickerResult[2])
            }
            
            
        }
        .edgesIgnoringSafeArea(.bottom)
        .navigationBarTitle("Select Photo", displayMode: .inline)
        .navigationBarItems(trailing: selectPhotoButton)
        .sheet(isPresented: $photoPickerIsPresented) {
          PhotoPicker(pickerResult: $pickerResult,
                      isPresented: $photoPickerIsPresented)
        }
      }
    }
    
    @ViewBuilder
    private var selectPhotoButton: some View {
      Button(action: {
        photoPickerIsPresented = true
      }, label: {
        Label("Select", systemImage: "photo")
      })
    }
    
}

我的问题是,由于某种未知原因,每次我选择照片并尝试添加它们时,应用程序都会崩溃。如果我pickerResult[0]对所有三个都这样做,它工作得很好,但在所有 3 个点上只显示第一张选定的照片。此外,如果我从所有 3 个 as 开始pickerResult[0],然后[0], [1], [2]在预览运行时将它们更改为,它不会崩溃并正确显示。

我只是从 Swift 和 SwiftUI 开始,如果这是一些基本的错误,请原谅。下面我还添加了我从我找到的一篇文章中获得的 PhotoPicker 代码。

在此处输入图像描述

PhotoPicker.swift:

import SwiftUI
import PhotosUI

struct PhotoPicker: UIViewControllerRepresentable {
  @Binding var pickerResult: [UIImage]
  @Binding var isPresented: Bool
  
  func makeUIViewController(context: Context) -> some UIViewController {
    var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
    configuration.filter = .images // filter only to images
    if #available(iOS 15, *) {
        configuration.selection = .ordered //number selection
    }
    configuration.selectionLimit = 3 // ignore limit
    
    let photoPickerViewController = PHPickerViewController(configuration: configuration)
    photoPickerViewController.delegate = context.coordinator
    return photoPickerViewController
  }
  
  func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
  
  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }
  
  class Coordinator: PHPickerViewControllerDelegate {
    private let parent: PhotoPicker
    
    init(_ parent: PhotoPicker) {
      self.parent = parent
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
      parent.pickerResult.removeAll()
      
      for image in results {
        if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
          image.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] newImage, error in
            if let error = error {
              print("Can't load image \(error.localizedDescription)")
            } else if let image = newImage as? UIImage {
              self?.parent.pickerResult.append(image)
            }
          }
        } else {
          print("Can't load asset")
        }
      }
      
      parent.isPresented = false
    }
  }
}
4

1 回答 1

1

image.itemProvider.loadObject是一个异步函数,它会一张一张地加载图片。

处理完第一张图像后,您将其添加到pickerResult并且您的pickerResult.isEmpty检查变为false,但您的数组到目前为止仅包含一个项目。

这里安全的做法是检查计数:

if pickerResult.count == 3 {
    CollageLayoutOne(uiImageOne: pickerResult[0], uiImageTwo: pickerResult[1], uiImageThree: pickerResult[2])
}

此外,在这种情况下,最好等到所有异步请求都完成后再更新 UI,例如,如下所示:

var processedResults = [UIImage]()
var leftToLoad = results.count
let checkFinished = { [weak self] in
    leftToLoad -= 1
    if leftToLoad == 0 {
        self?.parent.pickerResult = processedResults
        self?.parent.isPresented = false
    }
}
for image in results {
    if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
        image.itemProvider.loadObject(ofClass: UIImage.self) { newImage, error in
            if let error = error {
                print("Can't load image \(error.localizedDescription)")
            } else if let image = newImage as? UIImage {
                processedResults.append(image)
            }
            checkFinished()
        }
    } else {
        print("Can't load asset")
        checkFinished()
    }
}
于 2022-02-17T04:44:01.053 回答