我正在尝试使用PHPickerViewController和可组合体系结构来实现SwiftUI。(我并不认为这是特别相关的,但它可能解释了为什么我的一些代码是这样的)。
样本工程
我一直在玩这个来解决这个问题。我在GitHub上创建了一个小示例项目,它删除了可组合体系结构,并保持UI超级简单。
https://github.com/oliverfoggin/BrokenImagePickers/tree/main
看起来iOS 15在UIImagePickerViewController和PHPickerViewController上都要崩溃了。(这是有意义的,因为他们都在引擎盖下使用相同的UI )。
我想下一步是确定在UIKit应用程序中使用它们时是否会发生相同的错误。
我的代码
我的代码非常直接。这只是使用UIImagePickerViewController的相同特性的重新实现,但我想尝试使用较新的API。
我的密码是这样的..。
public struct ImagePicker: UIViewControllerRepresentable {
// Vars and setup stuff...
@Environment(\.presentationMode) var presentationMode
let viewStore: ViewStore<ImagePickerState, ImagePickerAction>
public init(store: Store<ImagePickerState, ImagePickerAction>) {
self.viewStore = ViewStore(store)
}
// UIViewControllerRepresentable required functions
public func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> some UIViewController {
// Configuring the PHPickerViewController
var config = PHPickerConfiguration()
config.filter = PHPickerFilter.images
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
public func makeCoordinator() -> Coordinator {
Coordinator(self)
}
// This is the coordinator that acts as the delegate
public class Coordinator: PHPickerViewControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let itemProvider = results.first?.itemProvider,
itemProvider.canLoadObject(ofClass: UIImage.self) else {
return
}
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
if let image = image as? UIImage {
DispatchQueue.main.async {
self?.parent.viewStore.send(.imagePicked(image: image))
}
}
}
}
}
}所有这些都适用于简单的情况。
我可以呈现ImagePicker视图并选择一张照片,这一切都很好。我可以取消它,好吗?我甚至可以向下滚动我拥有的图像的巨大集合视图。我甚至可以看到新的图像出现在我的状态对象,并显示在我的应用程序。(注.这仍然是WIP,所以代码有点笨重,但这只是为了让它开始工作)。
问题案例
问题是,当我点击PHPickerView中的搜索栏(这是苹果在控件中提供的搜索栏)时,我没有创建它,也没有编写它)。它似乎开始在键盘上滑动,然后视图变成空白,中间只有一条消息.
无法加载照片
再试试
我还得到了一个奇怪的错误日志。(我删除了时间戳,以缩短线条)。
// These happen on immediately presenting the ImagePicker
AppName[587:30596] [Picker] Showing picker unavailable UI (reason: still loading) with error: (null)
AppName[587:30596] Writing analzed variants.
// These happen when tapping the search bar
AppName[587:30867] [lifecycle] [u A95D90FC-C77B-43CC-8FC6-C8E7C81DD22A:m (null)] [com.apple.mobileslideshow.photospicker(1.0)] Connection to plugin interrupted while in use.
AppName[587:31002] [lifecycle] [u A95D90FC-C77B-43CC-8FC6-C8E7C81DD22A:m (null)] [com.apple.mobileslideshow.photospicker(1.0)] Connection to plugin invalidated while in use.
AppName[587:30596] [Picker] Showing picker unavailable UI (reason: crashed) with error: (null)
AppName[587:30596] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}点击“重试”按钮重新加载初始滚动屏幕,我可以继续使用它。但是再次点击搜索栏只会显示同样的错误。
我通常是第一个指出这个错误的人,几乎肯定不是Apple的错误,但是这个错误让我很困惑。我不知道我在做什么会导致这种事发生?
是因为它在SwiftUI视图中吗?
在UIKit中重新创建该项目
我用UIKit重做了同一个项目..。https://github.com/oliverfoggin/UIKit-Image-Pickers
我根本无法复制那次坠机。
还有..。如果您正在对设备进行任何类型的屏幕记录,则不会发生崩溃。我试着在设备上录了一段录音,但无法复制。我还试着用iPhone屏幕从我的Mac电脑上录制一段电影,但无法复制崩溃。但是..。当我在QuickTime上停止录音的时候,坠机又被复制了。
发布于 2022-02-10 17:27:38
这个为我修复了,就像.ignoreSafeArea(.keyboard)提到的那样。
要详细说明@Frustrated_Student,这个问题与UIViewControllerRepresentable有关,它像对待许多SwiftUI视图一样对待视图,以自动避免键盘。如果您像我一样使用工作表来呈现选择器,那么您可以简单地将.ignoreSafeArea(.keyboard)添加到UIViewControllerRepresentable视图中--在我的例子中--这里称之为ImagePicker是一个更好的例子。
在哪里添加.ignoreSafeArea(.keyboard)
.sheet(isPresented: $imagePicker) {
ImagePicker(store: store)
.ignoresSafeArea(.keyboard)
}这是@Fogmeister代码:
public struct ImagePicker: UIViewControllerRepresentable {
// Vars and setup stuff...
@Environment(\.presentationMode) var presentationMode
let viewStore: ViewStore<ImagePickerState, ImagePickerAction>
public init(store: Store<ImagePickerState, ImagePickerAction>) {
self.viewStore = ViewStore(store)
}
// UIViewControllerRepresentable required functions
public func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> some UIViewController {
// Configuring the PHPickerViewController
var config = PHPickerConfiguration()
config.filter = PHPickerFilter.images
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
return picker
}
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
public func makeCoordinator() -> Coordinator {
Coordinator(self)
}
// This is the coordinator that acts as the delegate
public class Coordinator: PHPickerViewControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let itemProvider = results.first?.itemProvider,
itemProvider.canLoadObject(ofClass: UIImage.self) else {
return
}
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
if let image = image as? UIImage {
DispatchQueue.main.async {
self?.parent.viewStore.send(.imagePicked(image: image))
}
}
}
}
}
}发布于 2021-09-25 10:00:51
好吧..。这似乎是一个iOS错误。
我在这里验证了一个示例项目,它显示了错误.https://github.com/oliverfoggin/BrokenImagePickers
还有一个用UIKit编写的复制项目.https://github.com/oliverfoggin/UIKit-Image-Pickers
我试图对这种情况进行屏幕记录,但是如果有任何屏幕记录正在发生(无论是在设备上还是通过Mac上的QuickTime ),这将抑制错误的发生。
我已经向苹果公司提交了一份雷达,并把这两个项目都发送给了他们,让他们看看正在发生的事情,并提供了很多细节。我会随时更新这方面的任何进展。
无趣的解决办法
经过进一步的研究,我发现您可以从SwiftUI开始,然后在不发生这种崩溃的情况下呈现一个PHPickerViewController。
如果你出示SwiftUI的UIViewControllerRepresentable..。然后从那里开始,如果出现PHPickerViewController,它就不会崩溃。
因此,我想出了一个(非常俗气的)解决办法,以避免这次坠机。
我首先创建一个像包装器一样使用的UIViewController子类。
class WrappedPhotoPicker: UIViewController {
var picker: PHPickerViewController?
override func viewDidLoad() {
super.viewDidLoad()
if let picker = picker {
present(picker, animated: false)
}
}
}然后在SwiftUI视图中创建这个包装器并在其中设置选择器。
struct WrappedPickerView: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var photoPickerResult: PHPickerResult?
let wrappedPicker = WrappedPhotoPicker()
func makeUIViewController(context: Context) -> WrappedPhotoPicker {
var config = PHPickerConfiguration()
config.filter = .images
config.selectionLimit = 1
let picker = PHPickerViewController(configuration: config)
picker.delegate = context.coordinator
wrappedPicker.picker = picker
return wrappedPicker
}
func updateUIViewController(_ uiViewController: WrappedPhotoPicker, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: PHPickerViewControllerDelegate {
let parent: WrappedPickerView
init(_ parent: WrappedPickerView) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
parent.presentationMode.wrappedValue.dismiss()
parent.wrappedPicker.dismiss(animated: false)
parent.photoPickerResult = results.first
}
}
}这是远远不理想的,因为我是在错误的时间和东西。但在苹果为这一问题提供永久解决方案之前,它是可行的。
发布于 2022-01-02 12:55:55
在PHPickerViewController崩溃后,我开始得到一个奇怪的UI错误,在那里键盘是不可见的,但我的视图仍然被压缩。所以我怀疑是键盘/回避问题。我在父视图中禁用了键盘避免,并设法阻止它崩溃。
.ignoresSafeArea(.keyboard)https://stackoverflow.com/questions/69306179
复制相似问题