iOS实现相册和网络图片的存取

2025-05-29 0 99

保存 uiimage 到相册

uikit

uikit 中一个古老的方法,objective-c 的形式

复制代码 代码如下:


void uiimagewritetosavedphotosalbum(uiimage *image, id completiontarget, sel completionselector, void *contextinfo);

保存完成后,会调用 completiontarget 的 completionselector。如果 completiontarget 不为空,completiontarget 必须实现以下方法

复制代码 代码如下:


– (void)image:(uiimage *)image didfinishsavingwitherror:(nserror *)error contextinfo:(void *)contextinfo;

objective-c 的写法

?

1

2

3

4

5

6

7

8

9

10

11
- (void)saveimage:(uiimage *)image {

uiimagewritetosavedphotosalbum(image, self, @selector(image:didfinishsavingwitherror:contextinfo:), nil);

}

- (void)image:(uiimage *)image didfinishsavingwitherror:(nserror *)error contextinfo:(void *)contextinfo {

if (error) {

// fail

} else {

// success

}

}

swift 的写法

?

1

2

3

4

5

6

7

8

9

10

11
func saveimage(_ image: uiimage) {

uiimagewritetosavedphotosalbum(image, self, #selector(image(_:didfinishsavingwitherror:contextinfo:)), nil)

}

func image(_ image: uiimage, didfinishsavingwitherror error: nserror?, contextinfo: anyobject) {

if error == nil {

// success

} else {

// fail

}

}

photos framework

ios 8 开始,可以用 photos framework。phassetchangerequest 的类方法可以保存 uiimage

复制代码 代码如下:


class func creationrequestforasset(from image: uiimage) -> self

编辑相册需要在 phphotolibrary 的闭包中进行,有两种方法

复制代码 代码如下:


func performchanges(_ changeblock: @escaping () -> void, completionhandler: ((bool, error?) -> void)? = nil)

复制代码 代码如下:


func performchangesandwait(_ changeblock: @escaping () -> void) throws

以上两种方法,分别是异步和同步执行。一般用第一种异步执行的方法,不会阻塞主线程。

?

1

2

3

4

5

6

7

8

9

10

11

12
func saveimage(_ image: uiimage) {

phphotolibrary.shared().performchanges({

phassetchangerequest.creationrequestforasset(from: image)

}, completionhandler: { (success, error) in

// not on main thread

if success {

// success

} else if let error = error {

// handle error

}

})

}

编辑相册的闭包 changeblock 和完成的闭包 completionhandler,是在 serial queue 中执行,不在主线程。需要更新 ui 的话,要切换到主线程中执行。

保存图片的 data 到相册

如果有图片的数据(data 或 nsdata),可以用 photos framework 的方法保存到相册。从 ios 9 开始,可以使用 phassetcreationrequest 的方法

复制代码 代码如下:


func addresource(with type: phassetresourcetype, data: data, options: phassetresourcecreationoptions?)

ios 8 比较麻烦,需要把数据写入临时文件,用临时文件的 url 作为参数,调用 phassetchangerequest 的类方法

复制代码 代码如下:


class func creationrequestforassetfromimage(atfileurl fileurl: url) -> self?

以下是兼容 ios 8 的写法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32
func saveimagedata(_ data: data) {

if #available(ios 9.0, *) {

phphotolibrary.shared().performchanges({

phassetcreationrequest.forasset().addresource(with: .photo, data: data, options: nil)

}, completionhandler: { (success, error) in

// not on main thread

if success {

// success

} else if let error = error {

// handle error

}

})

} else {

// write image data to temp file

let temppath = nstemporarydirectory().appending("tempimagetosavetophoto.image")

let tempurl = url(fileurlwithpath: temppath)

try? data.write(to: tempurl)

phphotolibrary.shared().performchanges({

phassetchangerequest.creationrequestforassetfromimage(atfileurl: tempurl)

}, completionhandler: { (success, error) in

// not on main thread

if success {

// success

} else if let error = error {

// handle error

}

// remove temp file

try? filemanager.default.removeitem(at: tempurl)

})

}

}

sdwebimage 缓存 uiimage、data

sdwebimage (目前版本 4.0.0) 有两个方法可以使用。

sdwebimagemanager 的方法

复制代码 代码如下:


– (void)saveimagetocache:(nullable uiimage *)image forurl:(nullable nsurl *)url;

sdimagecache 的方法

?

1

2

3

4

5
- (void)storeimage:(nullable uiimage *)image

imagedata:(nullable nsdata *)imagedata

forkey:(nullable nsstring *)key

todisk:(bool)todisk

completion:(nullable sdwebimagenoparamsblock)completionblock;

iOS实现相册和网络图片的存取

这个方法的 image、key 参数不能为空,否则直接执行 completionblock 就返回。

相册获取 uiimage、data

uiimagepickercontroller 是常用的照片选取控制器。实现一个代理方法即可

复制代码 代码如下:


optional func imagepickercontroller(_ picker: uiimagepickercontroller, didfinishpickingmediawithinfo info: [string : any])

通过 info 字典,可以获取 uiimage 等信息。这里用来查询 info 字典的 key 有

?

1

2

3
uiimagepickercontrolleroriginalimage // 原始 uiimage

uiimagepickercontrollereditedimage // 编辑后的 uiimage

uiimagepickercontrollerreferenceurl // alasset 的 url

通过 alasset 的 url 可获取 phasset。通过 phimagemanager 的方法可以获得相册图片的 data

复制代码 代码如下:


func requestimagedata(for asset: phasset, options: phimagerequestoptions?, resulthandler: @escaping (data?, string?, uiimageorientation, [anyhashable : any]?) -> void) -> phimagerequestid

以下是代码示例

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
func imagepickercontroller(_ picker: uiimagepickercontroller, didfinishpickingmediawithinfo info: [string : any]) {

picker.dismiss(animated: true, completion: nil)

if let image = info[uiimagepickercontrolleroriginalimage] as? uiimage {

// get original image

}

if let url = info[uiimagepickercontrollerreferenceurl] as? url,

let asset = phasset.fetchassets(withalasseturls: [url], options: nil).firstobject {

phimagemanager.default().requestimagedata(for: asset, options: nil, resulthandler: { (imagedata, _, _, _) in

if let data = imagedata {

// get image data

}

})

}

}

从 sdwebimage 的缓存中获取 uiimage、data

sdwebimage 给 uiimageview 提供了方法,方便获取、显示网络图片。如果需要获取下载的图片(进行保存到相册、上传至服务器等操作),可以用以下方法

?

1

2

3

4
- (nullable id <sdwebimageoperation>)loadimagewithurl:(nullable nsurl *)url

options:(sdwebimageoptions)options

progress:(nullable sdwebimagedownloaderprogressblock)progressblock

completed:(nullable sdinternalcompletionblock)completedblock;

swift 的代码示例

?

1

2

3

4

5

6

7

8

9

10

11

12

13
sdwebimagemanager.shared().loadimage(with: url, options: sdwebimageoptions(rawvalue: 0), progress: nil, completed: { [weak self] (cachedimage, imagedata, error, _, _, _) in

guard self != nil else { return }

if let image = cachedimage {

// get image

}

if let data = imagedata {

// get image data

}

if error != nil {

// handle error

}

})

这个方法有个问题,对于静态图片,可能获取不到 data。如果需要获取图片 data 的话,不能直接这么写。查看源码可以找到原因。sdwebimagemanager 的 loadimage: 方法会调用 sdimagecache 的 querycacheoperationforkey: 方法

iOS实现相册和网络图片的存取

diskimagedatabysearchingallpathsforkey: 方法用来获取 disk 中图片的 data。当图片在 memory 中,只有 gif 图片才会提供 data,静态图的 data 为空;当图片在 disk 中,都会提供 data。如果能在外部直接调用 diskimagedatabysearchingallpathsforkey: 方法就很简单,但是不行,这是私有方法,只写在 .m 文件里,对外不可见。

改源码可以解决问题,将上图第一个箭头的 if 判断去掉,总是调用 diskimagedatabysearchingallpathsforkey: 方法。然而,改第三方库源码不好,可能会有想不到的糟糕后果。

一种方法是,根据 diskimageexistswithkey: 方法,获取 disk 上的 data。

iOS实现相册和网络图片的存取

判断 disk 的图片是否存在,就是查找两个路径。同样,拿到这两个路径的文件就可以获得 data。以下是 swift 代码示例

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24
sdwebimagemanager.shared().diskimageexists(for: imageurl) { [weak self] (exist) in

// always on main thread

guard self != nil else { return }

if exist {

// find image data from disk

var data: nsdata?

// get cache key

let key = sdwebimagemanager.shared().cachekey(for: imageurl)

// get cache path

if let path = sdimagecache.shared().defaultcachepath(forkey: key) {

data = nsdata(contentsoffile: path)

if data == nil {

data = nsdata(contentsoffile: (path as nsstring).deletingpathextension)

}

}

if data != nil {

// get image data

} else {

// fail getting image data

}

} else {

// no disk image

}

}

这个方法缺点在于,代码复杂,可能会在 sdwebimage 版本升级后失效(例如,disk 缓存路径改变)。

推荐的方法是,将图片缓存从 memory 中移除,然后调用 sdwebimagemanager 的 loadimage: 方法。

?

1

2

3

4

5

6

7

8

9

10

11

12

13
// get cache key

let key = sdwebimagemanager.shared().cachekey(for: imageurl)

// remove memory cache

sdimagecache.shared().removeimage(forkey: key, fromdisk: false, withcompletion: nil)

// load image and data

sdwebimagemanager.shared().loadimage(with: imageurl, options: sdwebimageoptions(rawvalue: 0), progress: nil) { [weak self] (_, data, _, _, _, _) in

guard self != nil else { return }

if data != nil {

// get image data

} else {

// fail getting image data

}

}

这样写比较简洁。即使 sdwebimage 版本升级后改变 disk 缓存路径,依然有效。以上代码执行之后,当前图片又会存在 memory 中。

遗留问题

将 jpg 图片的 data 保存至相册,然后再取出的 data 与保存的 data 可能不一样。requestimagedata: 方法传入 phimagerequestoptions,phimagerequestoptions 的 version 试了三种值(current、unadjusted、original)都不行。png、gif 图片还没遇到这个问题。可能保存 jpg 图片的过程会修改原始数据。如何使存取的数据一致?欢迎交流!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 iOS实现相册和网络图片的存取 https://www.kuaiidc.com/90915.html

相关文章

发表评论
暂无评论