我正在尝试确定是否是我的代码导致了问题,或者我是否应该向 Apple 提交错误报告。
在一个新项目中,我有以下代码:
import SwiftUI
struct ContentView: View {
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
@State private var image: Image?
var body: some View {
ZStack {
Rectangle()
.fill(Color.secondary)
if image != nil {
image?
.resizable()
.scaledToFit()
} else {
Text("Tap to select a picture")
.foregroundColor(.white)
.font(.headline)
}
}
.onTapGesture {
self.showingImagePicker = true
}
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage){
SystemImagePicker(image: self.$inputImage)
}
}
func loadImage() {
guard let inputImage = inputImage else { return }
image = Image(uiImage: inputImage)
}
}
import PhotosUI
import SwiftUI
struct SystemImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) private var presentationMode
@Binding var image: UIImage?
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration()
configuration.selectionLimit = 1
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
}
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
class Coordinator: NSObject, PHPickerViewControllerDelegate {
let parent: SystemImagePicker
init(parent: SystemImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
for img in results {
guard img.itemProvider.canLoadObject(ofClass: UIImage.self) else { return }
img.itemProvider.loadObject(ofClass: UIImage.self) { image, error in
if let error = error {
print(error)
return
}
guard let image = image as? UIImage else { return }
self.parent.image = image
self.parent.presentationMode.wrappedValue.dismiss()
}
}
}
}
}
但是,当仅选择一个图像时(根据我的代码,不选择然后“改变主意”并选择另一个不同的图像),在 Xcode 中运行内存图时会出现这些泄漏。
这是我的代码,还是Apple上的代码?
无论如何,图像选择器上的
Cancel
按钮也不起作用。因此,用户不能只是关闭选择器表,必须选择图像来关闭该表。
以前,我曾将此代码用于旧的
UIImagePickerController
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
deinit {
print("deinit")
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}
这也会导致选择图像时发生泄漏,但数量要少得多:
我知道你问这个问题已经一年多了,但希望这对你或其他寻找答案的人有帮助。
我在帮助文件中使用了这段代码:
import SwiftUI
import PhotosUI
struct ImagePicker: UIViewControllerRepresentable {
let configuration: PHPickerConfiguration
@Binding var selectedImage: UIImage?
@Binding var showImagePicker: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> PHPickerViewController {
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
}
extension ImagePicker {
class Coordinator: NSObject, PHPickerViewControllerDelegate {
private let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true) {
self.parent.showImagePicker = false
}
guard let provider = results.first?.itemProvider else { return }
if provider.canLoadObject(ofClass: UIImage.self) {
provider.loadObject(ofClass: UIImage.self) { image, _ in
self.parent.selectedImage = image as? UIImage
}
}
parent.showImagePicker = false
}
}
}
这在您的视图中(我在此处设置了配置,以便我可以根据我使用选择器的用途传递自定义版本,提供了 2 个):
@State private var showImagePicker = false
@State private var selectedImage: UIImage?
@State private var profileImage: Image?
var profileConfig: PHPickerConfiguration {
var config = PHPickerConfiguration()
config.filter = .images
config.selectionLimit = 1
config.preferredAssetRepresentationMode = .current
return config
}
var mediaConfig: PHPickerConfiguration {
var config = PHPickerConfiguration()
config.filter = .any(of: [.images, .videos])
config.selectionLimit = 1
config.preferredAssetRepresentationMode = .current
return config
}
这会进入你的身体。你可以按照你想要的方式定制它,但这就是我所拥有的,所以我不想尝试将它拼凑出来:
HStack {
Button {
showImagePicker.toggle()
} label: {
Text("Select Photo")
.foregroundColor(Color("AccentColor"))
}
.sheet(isPresented: $showImagePicker) {
loadImage()
} content: {
ImagePicker(configuration: profileConfig, selectedImage: $selectedImage, showImagePicker: $showImagePicker)
}
}
if profileImage != nil {
profileImage?
.resizable()
.scaledToFill()
.frame(width: 100, height: 100)
.clipShape(Circle())
.shadow(radius: 5)
.overlay(Circle().stroke(Color.black, lineWidth: 2))
}
else {
Image(systemName: "person.crop.circle")
.resizable()
.foregroundColor(Color("AccentColor"))
.frame(width: 100, height: 100)
}
我还会为您提供加载图像的功能(我将重新放大:
func loadImage() {
guard let selectedImage = selectedImage else { return }
profileImage = Image(uiImage: selectedImage)
}
我还在我的表单上使用它来更新图像(如果图像发生更改),但您可以将它用于您用于身体的任何内容(列表、表单等。无论需要 .onChange):
.onChange(of: selectedImage) { _ in
loadImage()
}
我注意到在很多教程中几乎没有提到这一行,这就是取消按钮功能的原因(我不知道关闭是否是必要的,但我添加了它并且它起作用了,所以我把它留在了示例中):
picker.dismiss(animated: true)
我希望我添加的所有内容都能对您有所帮助。它似乎没有泄漏任何内容,并且让您可以使用取消按钮。
祝你好运!