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

iOS Swift 5中从相机/相册选图:预判断大小及最优方案

iOS相册多选/相机拍照上传:预加载判断图片大小与最优实现方案

一、能不能在加载进应用前判断图片大小?

完全可以:

  • 相册选图:借助Photos框架的PHAsset,可以直接获取原图的文件大小,无需将图片解码为UIImage加载到内存中。
  • 相机拍照:拍照完成后,系统会返回图片的本地文件路径,直接读取该路径的文件大小即可,同样不需要先加载图片。

二、最优实现方案

1. 相册选图:通过PHAsset获取单图大小

首先导入Photos框架,在用户选完图片后,通过PHAsset异步获取图片大小(不占用额外内存):

import Photos

// 异步获取PHAsset对应的文件大小
func getAssetFileSize(_ asset: PHAsset, completion: @escaping (Int64?) -> Void) {
    let options = PHImageRequestOptions()
    options.isSynchronous = false
    options.deliveryMode = .highQualityFormat
    
    PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { _, _, _, info in
        let fileSize = info?[PHImageFileSizeKey] as? Int64
        completion(fileSize)
    }
}

如果使用iOS14+推荐的PHPickerViewController,可以从PHPickerResult中提取PHAsset:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    let assets = results.compactMap { $0.assetIdentifier }.compactMap { PHAsset.fetchAssets(withLocalIdentifiers: [$0], options: nil).firstObject }
    
    // 批量获取大小
    var totalSize: Int64 = 0
    let group = DispatchGroup()
    for asset in assets {
        group.enter()
        getAssetFileSize(asset) { size in
            if let size = size {
                totalSize += size
            }
            group.leave()
        }
    }
    group.notify(queue: .main) {
        // 校验总大小
        self.checkTotalSize(totalSize)
    }
}

2. 相机拍照:读取本地文件大小

相机拍照完成后,从UIImagePickerController的info字典中获取图片本地URL,直接读取文件大小:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true)
    
    guard let imageURL = info[.imageURL] as? URL else { return }
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: imageURL.path)
        guard let fileSize = fileAttributes[.size] as? Int64 else { return }
        
        // 校验是否可以加入已选列表
        if checkCanAddImage(size: fileSize) {
            // 处理后续逻辑,比如保存URL或asset
        }
    } catch {
        print("读取图片大小失败:\(error)")
    }
}

3. 总大小校验逻辑

维护一个变量记录已选图片总大小,每次新增前判断是否超出5MB限制:

private var totalSelectedSize: Int64 = 0
private let maxTotalSize: Int64 = 5 * 1024 * 1024 // 5MB

private func checkCanAddImage(size: Int64) -> Bool {
    guard totalSelectedSize + size <= maxTotalSize else {
        let alert = UIAlertController(title: "提示", message: "已选图片总大小超过5MB限制,请减少图片或选择更小的文件", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        present(alert, animated: true)
        return false
    }
    totalSelectedSize += size
    return true
}

// 重置总大小(比如用户取消选择时)
private func resetTotalSize() {
    totalSelectedSize = 0
}

4. 额外优化建议

  • 优先用PHPicker:iOS14+推荐使用PHPickerViewController,它不需要请求相册全权限,仅请求选中图片的权限,用户体验更好,多选支持更完善。
  • 批量处理提升效率:如果是多选场景,用DispatchGroup批量获取所有图片大小,避免逐个处理的等待时间。
  • 提供压缩备选方案:如果用户选中的单图或总大小超出限制,除了提示,还可以提供图片压缩功能(比如调整分辨率、降低JPEG质量),提升用户体验:
    // 简单的图片压缩方法
    func compressImage(_ image: UIImage, targetSizeMB: CGFloat) -> Data? {
        var compressionQuality: CGFloat = 1.0
        var imageData = image.jpegData(compressionQuality: compressionQuality)
        while let data = imageData, Double(data.count) / (1024*1024) > targetSizeMB, compressionQuality > 0.1 {
            compressionQuality -= 0.1
            imageData = image.jpegData(compressionQuality: compressionQuality)
        }
        return imageData
    }
    
  • 内存优化:不要在不必要的时候保留UIImage实例,处理完上传逻辑后及时释放,避免内存飙升。

内容的提问来源于stack exchange,提问作者Prabhu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:56:01