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

如何通过NSItemProvider快速获取PHPicker选中的媒体文件大小?

iOS 基于PHPickerResult快速获取选中视频文件大小的方案

针对PHPicker选中媒体资源后无需加载完整文件即可提前校验大小的需求,有两种可行实现方案,按优先级从高到低排列如下:

方案1:直接读取NSItemProvider自带的suggestedFileSize属性(推荐,无额外耗时)

iOS 14+ 中NSItemProvider自带suggestedFileSize属性,存储系统提前缓存的文件大小元数据,无需任何IO操作即可读取,单位为字节。
示例代码:

import UniformTypeIdentifiers

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    guard let result = results.first, 
          result.itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) else {
        picker.dismiss(animated: true)
        return
    }
    let itemProvider = result.itemProvider
    // 优先读取缓存的文件大小
    if let fileSize = itemProvider.suggestedFileSize as? Int64, fileSize > 0 {
        // 示例限制为100MB,可根据业务调整
        let maxAllowedSize: Int64 = 100 * 1024 * 1024
        if fileSize > maxAllowedSize {
            // 直接提示超出大小限制,无需后续加载
            picker.dismiss(animated: true)
            // 此处添加你的大小超限提示逻辑
            return
        }
        // 大小符合要求,继续执行文件加载逻辑
    } else {
        // 缓存大小不可用,走方案2读取
        fetchVideoSizeFromItemProvider(itemProvider: itemProvider, picker: picker)
    }
}

方案2:加载安全作用域URL读取文件属性(兜底方案,耗时极低)

当suggestedFileSize返回0或nil时,通过loadItem读取资源的安全作用域URL,仅读取文件属性无需加载完整文件,耗时远低于loadFileRepresentation。
示例代码:

private func fetchVideoSizeFromItemProvider(itemProvider: NSItemProvider, picker: PHPickerViewController) {
    itemProvider.loadItem(forTypeIdentifier: UTType.movie.identifier, options: nil) { item, error in
        DispatchQueue.main.async {
            guard let url = item as? URL, error == nil else {
                picker.dismiss(animated: true)
                return
            }
            // 开启安全作用域访问权限
            guard url.startAccessingSecurityScopedResource() else {
                picker.dismiss(animated: true)
                return
            }
            // 退出作用域时自动关闭安全访问权限
            defer {
                url.stopAccessingSecurityScopedResource()
            }
            do {
                let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path)
                guard let fileSize = fileAttributes[.size] as? Int64 else {
                    picker.dismiss(animated: true)
                    return
                }
                let maxAllowedSize: Int64 = 100 * 1024 * 1024
                if fileSize > maxAllowedSize {
                    // 大小超限提示逻辑
                    picker.dismiss(animated: true)
                    return
                }
                // 大小符合要求,继续执行loadFileRepresentation加载完整文件
            } catch {
                picker.dismiss(animated: true)
            }
        }
    }
}

注意事项

  • 两种方案都仅针对资源元数据进行读取,不会拷贝完整视频文件到App沙盒,耗时远低于直接调用loadFileRepresentation
  • 安全作用域URL的startAccessingSecurityScopedResource和stopAccessingSecurityScopedResource必须成对调用,否则会出现权限错误
  • 若选中的是iCloud同步的资源,方案2需要等待少量元数据同步时间,但仍然远快于完整文件加载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:45:08