如何通过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
相关产品推荐
相关产品推荐

