保存多张图片

好了,函数签名就介绍完了,本身并不复杂,如果你在搜索引擎中查找的话,可能会看到很多例子会这样写:

UIImageWriteToSavedPhotosAlbum(imageWantToSave,nil,nil,nil)

只传入了第一个 image 参数,后面三后参数都传入nil。 这样调用在大多数情况下也都没有问题。图片正常的保存到了系统相册,一行代码完成了我们的需求,看起来方便又好用。

但在某些情况下,这个调用方式就会有问题了。比如这样:

forimageinimageList {UIImageWriteToSavedPhotosAlbum(image,nil,nil,nil)}

这里的imageList是一个图片数组,会包含多张图片,如果运行这样的代码,你就会发现你的图片保存会经常出错。 比如imageList里面有 10 张图片,可能在有些时候只能成功保存 4 张,后面的 6 张图片既没看到报错信息,也没成功。 但在另一些时候又能成功的把这 10 张图片都保存下来。

这种介于中间态的不确定状态是最让人头疼的。说它有问题,但不是每次都失败。说它没问题,但总有一些时候会失败,而且频率还不低。甚至会引起你对系统库本身稳定性的怀疑。

其实导致这个问题的原因,就是你少传入了第 2,3 个参数。 当然,如果说是系统库稳定性的问题,也不是完全没有道理。 不过与其说是稳定性,更提贴切的说法是这个函数的接口设计不够完善,容易让大家造成误解。

第 2,3 个参数用于指定一个接收完成事件的实例和方法,可以这样:

funcsaveImage(){forimageinimageList {UIImageWriteToSavedPhotosAlbum(image,self, #selector(self.imageSaveFinished(image:error:context:)),nil)}}func imageSaveFinished(image: UIImage, error: Error, context: UnsafeRawPointer){print(error)}

这次指定了imageSaveFinished方法作为UIImageWriteToSavedPhotosAlbum函数的回调事件。 它接受三个参数,image表示正在保存的图片,error代表保存过程中发生的错误,context代表上下文信息,前面我们提到过。

imageSaveFinished用 print 方法打印出错误信息。 再重新运行一下项目,就会在控制台上看到类似这样的输出:

There was a problem writing thisasset because the writing resources are busy.

这个错误原因从字面上就可以看出来,是因为写入操作过于频繁,导致了写入失败。 因为看不到UIImageWriteToSavedPhotosAlbum的源码,所以它的内部机制不得而知,我们能得到的线索就是不能在同一个线程对它连续频繁调用。

从这个错误还可以得到一个信息,就是之所以会发生这个错误,是因为前面的写入操作还没有执行完成,就开始了下一个。那么我们是不是可以对调用做一个简单处理呢,等到上一个操作完成在进行下一个写入?

以现有的接口其实是可以做到的,还回到imageSaveFinished方法上来,我们可以在每次写入成功后,再调用UIImageWriteToSavedPhotosAlbum方法写入下一个图片,这样就不会发生连续写入图片导致的写入错误了:

func saveImage(){ifself.imageList.count> 0{ifletimage = self.imageList.first {UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.imageSaveFinished(image:error:context:)), nil) } }}func imageSaveFinished(image: UIImage, error: Error, context: UnsafeRawPointer){self.imageList.removeFirst()ifself.imageList.count> 0{saveImage() } }

这次把saveImage方法改写了一下,每次调用,它只去imageList中第一个图片。 并且imageList也被声明成属性,可以跨方法访问。 然后在成功回调imageSaveFinished中,首先删除 imageList 中的第一张图片,也就这次保存成功的,然后判断imageList在删除后是否还有其他图片,如果有,那么继续调用saveImage方法保存。

这样,图片的保存就变成了顺序执行,只有上一张图片保存完成后,后面的图片才能开始保存。避免了频繁操作的问题。当然这里写的还是稍微简单,你还可以把它写的更健壮一些,比如在imageSaveFinished里面判断 error 是否为 nil 来界定回调发生时候图片是否真正的被保存成功。

但这个整体逻辑是没问题的,修改完成后在运行这个程序,你就会看到所有的批量图片保存操作都能成功的完成了。 再也不会出现之前的间歇性抽风问题了~

结束

UIImageWriteToSavedPhotosAlbum是 iOS 提供的一个非常方便的图片存储接口,大多数情况下它的使用很简单。当然对于保存多张图片的时候,还需要进行一些额外的处理,但总体还是很方便。在 iOS 10 以后的设备上使用它还需要注意一个细节,就是你需要在Info.plist中声明一个权限字段:

NSPhotoLibraryUsageDeion保存图片

这个字段用于给用户说明 APP 使用这个权限用来做什么,如果你声明这个字段,在 iOS 10 的设备上调用这个方法就会导致 Crash。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐