Swift:URL图片下载存相册需求及TableView选图存相册失败问题
解决Swift中选中TableView图片无法保存到系统相册的问题
看起来你已经搞定了从URL加载图片并在TableView展示的部分,现在卡在保存到系统相册这一步对吧?我来帮你梳理下核心问题和具体的解决办法:
1. 先搞定相册权限(必做!)
iOS系统对相册访问有严格的权限控制,没申请权限的话保存操作会直接失败,而且不会有明显提示。你需要在Info.plist中添加以下两个权限描述(适配不同iOS版本):
- 针对iOS 11及以上:添加
NSPhotoLibraryAddUsageDescription,值填你需要向用户说明的权限用途,比如"需要保存图片到你的相册" - 针对iOS 10及以下:添加
NSPhotoLibraryUsageDescription,同样填写权限用途
你可以直接在Info.plist的可视化编辑器里添加,也可以用源码模式添加:
<key>NSPhotoLibraryAddUsageDescription</key> <string>需要保存图片到你的相册</string> <key>NSPhotoLibraryUsageDescription</key> <string>需要访问你的相册以保存图片</string>
2. 实现选中cell后的保存逻辑
首先你需要在tableView(_:didSelectRowAt:)方法里拿到选中的图片,然后调用系统API保存。这里给你两种常用的实现方式:
方式一:用系统原生的UIImageWriteToSavedPhotosAlbum(简单快捷)
这个API是iOS早期就有的,使用起来很方便,还能通过回调获取保存结果:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 假设你的Datavalues模型里有已经下载好的UIImage对象,比如叫image guard let targetImage = parsingdata[indexPath.row].image else { print("图片对象为空,无法保存") return } // 调用保存方法 UIImageWriteToSavedPhotosAlbum(targetImage, self, #selector(imageSavedSuccessfully(_:didFinishSavingWithError:contextInfo:)), nil) } // 保存结果的回调方法 @objc func imageSavedSuccessfully(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { if let error = error { print("保存失败:\(error.localizedDescription)") // 这里可以给用户弹个提示,比如UIAlertController } else { print("保存成功!") // 提示用户保存成功 } }
方式二:用Photos框架(更现代、灵活的方式)
如果你的APP需要更复杂的相册操作(比如创建自定义相册),推荐用Photos框架,需要先导入Photos:
import Photos func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard let targetImage = parsingdata[indexPath.row].image else { print("图片对象为空,无法保存") return } // 检查权限状态 PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { switch status { case .authorized, .limited: // 权限通过,开始保存 PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAsset(from: targetImage) }) { success, error in DispatchQueue.main.async { if let error = error { print("保存失败:\(error.localizedDescription)") } else { print("保存成功!") } } } case .denied, .restricted: print("相册权限被拒绝,请在设置中开启") // 提示用户去设置里开启权限 case .notDetermined: // 一般不会走到这里,因为我们已经requestAuthorization了 break @unknown default: break } } } }
3. 排查常见坑点
- 确保图片对象不为空:你要确认
parsingdata[indexPath.row].image是已经下载完成的UIImage,而不是占位图或者nil - 主线程更新UI:所有弹提示、更新UI的操作都要放在主线程,上面的代码里已经用
DispatchQueue.main.async处理了 - 测试真机:模拟器的相册有时候会有兼容性问题,建议用真机测试保存功能
内容的提问来源于stack exchange,提问作者user8797533
相关产品推荐
相关产品推荐

