You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHPickerViewController无法将选中图片加载至UIButton问题排查

PHPicker选择图片后无法在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 11:45:41