cjnnd 2025-05-21 19:02 采纳率: 0%
浏览 17

Xcode 更新后 图片功能 返回空 解决方案

在Xcode更新后的16型号的所有模拟器打开图片选择器的时候都会加载进入后卡死,但是在15及15以下的还是可以正常使用,这应该是什么问题,使用的都是原生控件,不是第三方

img

import UIKit
import PhotosUI

extension ChatViewController: PHPickerViewControllerDelegate {
    func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
        let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)

        switch status {
        case .notDetermined:
            // 请求权限
            PHPhotoLibrary.requestAuthorization(for: .readWrite) { newStatus in
                DispatchQueue.main.async {
                    completion(newStatus == .authorized)
                }
            }
        case .authorized:
            // 已授权
            completion(true)
        case .denied, .restricted:
            // 权限被拒绝或受限
            completion(false)
        @unknown default:
            completion(false)
        }
    }

    @objc func handleUpload() {
        print("点击了上传照片")
        
        // 检查相册权限
        checkPhotoLibraryPermission { [weak self] isAuthorized in
            DispatchQueue.main.async {
                guard let self = self else { return }
                if isAuthorized {
                    // 创建 PHPickerConfiguration
                    var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
                    print("将要创建图片选择器")
                    configuration.filter = .images // 只允许选择图片
                    configuration.selectionLimit = 1 // 限制选择数量为1
                    
                    // 创建 PHPickerViewController
                    let pickerViewController = PHPickerViewController(configuration: configuration)
                    pickerViewController.delegate = self
                    
                    print("当前线程: \(Thread.isMainThread ? "主线程" : "子线程")")
                    
                    // 禁用按钮
                    self.sendButton.isEnabled = false
                    self.voiceButton.isEnabled = false
                    self.keyboardButton.isEnabled = false
                    self.uploadButton.isEnabled = false
                    
                    // 弹出 PHPickerViewController
                    self.present(pickerViewController, animated: true, completion: nil)
                    print("创建图片选择器成功")
                } else {
                    self.showPermissionDeniedAlert(message: "您尚未授权访问相册,请在设置中开启权限。")
                }
            }
        }
    }

    func showPermissionDeniedAlert(message: String) {
        let alert = UIAlertController(title: "错误", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "去设置", style: .default, handler: { _ in
            if let url = URL(string: UIApplication.openSettingsURLString) {
                UIApplication.shared.open(url)
            }
        }))
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: nil))
        present(alert, animated: true, completion: nil)
    }

    // MARK: - PHPickerViewControllerDelegate
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        print("图片选择完成")
        
        // 恢复按钮状态
        DispatchQueue.main.async {
            self.sendButton.isEnabled = true
            self.voiceButton.isEnabled = true
            self.keyboardButton.isEnabled = true
            self.uploadButton.isEnabled = true
        }
        
        picker.dismiss(animated: true) {
            print("图片选择器已关闭")
        }
        
        // 处理选择的图片
        guard let provider = results.first?.itemProvider,
              provider.canLoadObject(ofClass: UIImage.self) else {
            print("未选择图片")
            return
        }
        
        provider.loadObject(ofClass: UIImage.self) { image, error in
            if let image = image as? UIImage {
                DispatchQueue.main.async {
                    self.showLoadingIndicator()
                    
                    self.onImageSizeExceeded = { message in
                        DispatchQueue.main.async {
                            // 在主线程中执行UI更新
                            self.view.makeToast(message, duration: 1.5, position: .center)
                        }
                    }
                    
                    DispatchQueue.global().async {
                        // 获取图片的文件名和 MIME 类型
                        let fileName: String
                        var mimeType: String
                        var imageData: Data?
                        
                        let maxFileSize: UInt64 = 10 * 1024 * 1024 // 10MB
                        
                        // 判断图片格式
                        if let jpegData = image.jpegData(compressionQuality: 0.5) { // 压缩质量
                            fileName = "image_\(UUID().uuidString).jpg"
                            mimeType = "image/jpeg"
                            imageData = jpegData
                            print("选择了jpeg格式的图片")
                        } else if let pngData = image.pngData() {
                            fileName = "image_\(UUID().uuidString).png"
                            mimeType = "image/png"
                            imageData = pngData
                            print("选择了png格式的图片")
                        } else {
                            DispatchQueue.main.async {
                                self.hideLoadingIndicator()
                                self.showErrorAlert(message: "不支持的图片格式")
                            }
                            return
                        }
                        
                        // 打印出上传文件的大小
                        print("上传文件大小:\(imageData?.count ?? 0) 字节")
                        
                        // 调用上传函数
                        if let imageData = imageData, imageData.count < maxFileSize {
                            APICaller.shared.uploadAttachments(fileName: fileName, mimeType: mimeType, fileData: imageData) { result in
                                DispatchQueue.main.async {
                                    self.hideLoadingIndicator()
                                    switch result {
                                    case .success(let response):
                                        self.attachmentFilePath = response.data
                                        print("上传成功,路径:\(self.attachmentFilePath)")
                                        // 更新 UI
                                        self.view.makeToast("上传成功", duration: 1.0, position: .center)
                                        self.updateUIWithAttachment(image: image, filePath: response.data)
                                        self.sendButton.isEnabled = true
                                        self.uploadButton.isEnabled = true
                                        self.keyboardButton.isEnabled = true
                                        self.voiceButton.isEnabled = true
                                    case .failure(let error):
                                        print("上传失败,错误:\(error.localizedDescription)")
                                        self.sendButton.isEnabled = true
                                        self.uploadButton.isEnabled = true
                                        self.keyboardButton.isEnabled = true
                                        self.voiceButton.isEnabled = true
                                        self.showErrorAlert(message: "上传失败,请稍后重试")
                                    }
                                }
                            }
                        } else {
                            DispatchQueue.main.async {
                                self.hideLoadingIndicator()
                                self.onImageSizeExceeded?("最大允许上传\(maxFileSize / (1024 * 1024))MB大小文件!")
                            }
                        }
                    }
                }
            } else if let error = error {
                print("加载图片失败: \(error.localizedDescription)")
            }
        }
    }

    func updateUIWithAttachment(image: UIImage, filePath: String) {
        print("更新 UI")
        self.attachmentImageView.image = image
        self.attachmentImageView.isHidden = false
        self.deleteAttachmentButton.isHidden = false
        self.inputContainerView.addSubview(self.attachmentImageView)
        self.inputContainerView.addSubview(self.deleteAttachmentButton)
        
        self.attachmentImageView.snp.makeConstraints { make in
            make.leading.equalTo(self.inputContainerView.snp.leading).offset(10)
            make.top.equalTo(self.inputContainerView.snp.top).offset(5)
            make.width.height.equalTo(40) // 可根据需要调整尺寸
        }
        self.deleteAttachmentButton.snp.makeConstraints { make in
            make.top.equalTo(self.attachmentImageView.snp.top)
            make.leading.equalTo(self.attachmentImageView.snp.leading).offset(40)
            make.width.height.equalTo(12) // 可根据需要调整尺寸
        }
        self.inputTextView.snp.remakeConstraints { make in
            make.leading.equalTo(self.inputContainerView.snp.leading).offset(10)
            make.top.equalTo(self.attachmentImageView.snp.bottom).offset(10)  // 使得文本框在图片下方
            make.trailing.equalTo(self.inputContainerView.snp.trailing).offset(-10)
            make.bottom.equalTo(self.inputContainerView.snp.bottom).offset(-5)
        }
        self.updateInputContainerViewHeight()
    }
    
    func showLoadingIndicator() {
        print("显示加载指示器")
        if activityIndicator == nil {
            activityIndicator = UIActivityIndicatorView(style: .large)
            activityIndicator?.color = .gray
            activityIndicator?.center = self.view.center
            activityIndicator?.hidesWhenStopped = true
            if let activityIndicator = activityIndicator {
                self.view.addSubview(activityIndicator)
            }
        }
        activityIndicator?.startAnimating()
    }
    
    func hideLoadingIndicator() {
        print("隐藏加载指示器")
        activityIndicator?.stopAnimating()
    }

    func showErrorAlert(message: String) {
        print("显示错误提示: \(message)")
        let alert = UIAlertController(title: "错误", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
    }

    // 删除附件
    @objc func handleDeleteAttachment() {
        print("删除附件")
        guard let attachmentFilePath = self.attachmentFilePath else { return }
        APICaller.shared.deleteAttachments(file_path: attachmentFilePath) { result in
            DispatchQueue.main.async{
                switch result {
                case .success(let response):
                    self.attachmentFilePath = nil
                    print("删除附件成功\(response)")
                    self.updateUIAfterAttachmentDeletion()
                    self.view.makeToast("删除成功", duration: 1.0, position: .center)
                case .failure(let error):
                    print("删除附件失败:\(error.localizedDescription)")
                    self.view.makeToast("删除失败,请稍后重试", duration: 1.5, position: .center)
                }
            }
        }
    }
}


  • 写回答

5条回答 默认 最新

  • 阿里嘎多学长 2025-05-21 19:02
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    Xcode 更新后 图片功能 返回空 解决方案

    你遇到的问题可能是 Xcode 16 中的 UIImagePickerController 的一个 bug。这个 bug 会导致图片选择器在模拟器上卡死。

    解决方案是:

    1. UIImagePickerController 中添加 mediaTypes 属性,并设置为 ["public.image"]
    let picker = UIImagePickerController()
    picker.mediaTypes = [.image]
    
    1. 如果上述方法不起作用,可以尝试使用 PHImageManager 来获取图片。
    let manager = PHImageManager.default()
    manager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: nil) { image, info in
        // 处理图片
    }
    
    1. 如果你使用的是 ALAssetsLibrary,可以尝试使用 ALAssetsLibraryassetForURL 方法来获取图片。
    let library = ALAssetsLibrary()
    library.assetForURL(url, resultBlock: { asset in
        // 处理图片
    }, failureBlock: { error in
        // 处理错误
    })
    

    这些解决方案都可以解决 Xcode 16 中的 UIImagePickerController bug。

    评论

报告相同问题?

问题事件

  • 创建了问题 5月21日