PHPickerViewController无法将选中图片加载至UIButton问题排查
问题描述
我通过代码创建了一个可选择头像的UIButton,使用PHPicker实现图片选择器,选择器能正常显示,但选中图片后无法在按钮上展示。尝试新下载的图片也存在同样问题,偶尔会显示白色背景或报错,控制台提示“Xxx(文件目录)无法打开,因为不存在该文件”。此前该PHPicker代码运行正常,请问如何解决图片选择后正常显示的问题?
相关代码
1. 头像按钮初始化
private let plusPhotoButton: UIButton = { let button = UIButton(type: .system) button.setImage(UIImage(named: "plus_photo"), for: .normal) button.tintColor = .white button.addTarget(self, action: #selector(imagePickerTapped), for: .touchUpInside) return button }()
2. 唤起图片选择器
@objc func imagePickerTapped() { print("imagePickerTapped") var configuration = PHPickerConfiguration() configuration.selectionLimit = 1 let picker = PHPickerViewController(configuration: configuration) picker.delegate = self self.present(picker, animated: true, completion: nil) }
3. PHPicker代理实现
// MARK: - PHPicker extention extension RegistrationController : PHPickerViewControllerDelegate { func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) let itemProvider = results.first?.itemProvider if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) { itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in DispatchQueue.main.async { self.plusPhotoButton.layer.cornerRadius = self.plusPhotoButton.frame.width / 2 self.plusPhotoButton.layer.masksToBounds = true self.plusPhotoButton.layer.borderColor = UIColor.black.cgColor self.plusPhotoButton.layer.borderWidth = 2 self.plusPhotoButton.setImage(image as? UIImage, for: .normal) } } } else { print("Image wasn't loaded!!!!") } } }
4. 按钮布局代码
view.addSubview(plusPhotoButton) plusPhotoButton.centerX(inView: view) plusPhotoButton.setDimensions(height: 140, width: 140) plusPhotoButton.anchor(top: view.safeAreaLayoutGuide.topAnchor, paddingTop: 32) let stack = UIStackView(arrangedSubviews: [emailTextField, passwordTextField, fullnameTextField, UsernameTextField, loginButton]) stack.axis = .vertical stack.spacing = 20 view.addSubview(stack) stack.anchor(top: plusPhotoButton.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 32, paddingLeft: 32, paddingRight: 32)
问题排查与解决方案
1. 修正布局时机错误
你在图片加载回调中用frame.width计算圆角,但Auto Layout下按钮的frame在此时可能未完全确定,导致样式设置失效或异常。
解决:
将按钮样式(圆角、边框)移到布局完成的时机:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() plusPhotoButton.layer.cornerRadius = plusPhotoButton.bounds.width / 2 plusPhotoButton.layer.masksToBounds = true plusPhotoButton.layer.borderColor = UIColor.black.cgColor plusPhotoButton.layer.borderWidth = 2 }
图片加载回调仅保留设置图片的逻辑:
itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in DispatchQueue.main.async { if let selectedImage = image as? UIImage { self.plusPhotoButton.setImage(selectedImage, for: .normal) } else { print("图片转换失败: \(error?.localizedDescription ?? "未知错误")") } } }
2. 优化图片加载方式
直接加载UIImage可能遇到权限或解码问题,改用加载图片数据再转UIImage的方式更稳定:
// 需先导入UniformTypeIdentifiers框架(iOS14+) if let itemProvider = itemProvider, itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) { itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, error in DispatchQueue.main.async { if let error = error { print("加载图片出错: \(error.localizedDescription)") return } if let data = data, let selectedImage = UIImage(data: data) { self.plusPhotoButton.setImage(selectedImage, for: .normal) } else { print("图片数据无效") } } } }
3. 调整按钮图片显示模式
UIButton默认的图片模式可能导致图片拉伸或显示不全,添加内容模式设置:
private let plusPhotoButton: UIButton = { let button = UIButton(type: .system) button.setImage(UIImage(named: "plus_photo"), for: .normal) button.tintColor = .white button.addTarget(self, action: #selector(imagePickerTapped), for: .touchUpInside) // 设置图片缩放模式 button.imageView?.contentMode = .scaleAspectFill return button }()
4. 验证自定义布局方法
检查centerX(inView:)、setDimensions、anchor这些自定义布局工具,确保它们正确设置了Auto Layout约束,而非直接修改frame,避免布局冲突导致按钮显示异常。
内容的提问来源于stack exchange,提问作者LEE
相关产品推荐
相关产品推荐

