记录Photos框架的使用

记录Photos框架的使用

前言

这几天项目里用到了图片选择器,就想把之前项目里用ALAssetsLibrary框架封装的图片选择器拿过来用,但是ALAssetsLibrary框架在9.0之后就被弃用了。所以,就要试试Photos框架了。
在网上找了几篇blog研究了一下,就搞了起来。期间也踩了几个坑,所以开篇记录一下。

第一波 获取用户相册

先介绍一些概念,大家可以参考一下这篇blog

  • PHAsset:代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源
  • PHFetchOptions:获取资源时的参数,可以传 nil,即使用系统默认值
  • PHFetchResult:表示一系列的资源集合,也可以是相册的集合
  • PHAssetCollection:表示一个相册或者一个时刻,或者是一个「智能相册(系统提供的特定的一系列相册,例如:最近删除,视频列表,收藏等等,如下图所示)
  • PHImageManager:用于处理资源的加载,加载图片的过程带有缓存处理,可以通过传入一个 PHImageRequestOptions 控制资源的输出尺寸等规格
  • PHImageRequestOptions:如上面所说,控制加载图片时的一系列参数

先上一段获取相册的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//所有智能相册
let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)

weak var weakSelf = self
DispatchQueue.global().async {
smartAlbums.enumerateObjects({ (collection, index, stop) in
if (collection.isKind(of: PHAssetCollection.self)) {
if (collection.localizedTitle == "Recently Added" || collection.localizedTitle == "All Photos") {
weakSelf?.allAlbums.append(collection)
}

}
})

DispatchQueue.main.async {
weakSelf?.tableView?.reloadData()
}
}

上述方法中的第一第二个参数的类型介绍:

  1. PHAssetCollectionType有三个值:

    • album:自定义相册,例如:QQ
    • smartAlbum:相机胶卷、我的照片流、屏幕截图、全景照片等
    • moment:时刻
  2. PHAssetCollectionSubtype一些值:

    • albumRegular:用户在Photos中创建的相册,也就是我所谓的逻辑相册
    • albumSyncedEvent:使用iTunes从Photos照片库或者iPhoto照片库同步过来的事件。然而,在iTunes 12以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
    • albumSyncedFaces:使用iTunes从Photos照片库或者iPhoto照片库同步的人物相册。
    • albumSyncedAlbum:做了AlbumSyncedEvent应该做的事
    • albumImported:从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。

从上面的方法中我们可以获取到用户相关的相册,collection.localizedTitle获取相册名字,对应的中英文对照如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
["Slo-mo" : "慢动作", 
"Recently Added" : "最近添加",
"Favorites" : "个人收藏",
"Recently Deleted" : "最近删除",
"Videos" : "视频",
"All Photos" : "所有照片",
"Selfies" : "自拍",
"Screenshots" : "屏幕快照",
"Camera Roll" : "相机胶卷",
"Panoramas" : "全景照片",
"Hidden" : "已隐藏",
"Time-lapse" : "延时拍摄",
"Bursts" : "连拍快照".
"Depth Effect" : "景深效果"]

第二波 获取相册中的资源

先来一波代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let options = PHFetchOptions()
options.sortDescriptors = [NSSortDescriptor.init(key: "creationDate", ascending: true)]
options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)
let fetchResult = PHAsset.fetchAssets(in: phCollection!, options: options)

weak var weakSelf = self
DispatchQueue.global().async {
fetchResult.enumerateObjects { (asset, index, stop) in
weakSelf?.dataSource.append(asset)
}

DispatchQueue.main.async {
...
}
}

代码中,通过谓词NSPredicate筛选出所有的照片资源。
PHAssetMediaType有四个值:

  • unknown:未知
  • image:图片
  • video:视频
  • audio:音频

PHAsset代表照片库中的一个资源,跟ALAsset类似,通过PHAsset我们可以获取和保存资源。
打印asset显示包含如下信息:

第三波 获取相册里的图片

废话不多说,直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DispatchQueue.global().async {
let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = .fast

weak var weakSelf = self
let manager = PHImageManager.default()
manager.requestImage(for: asset, targetSize: self.getTargetSize(), contentMode: .aspectFit, options: requestOptions, resultHandler: { (image, dic) in
DispatchQueue.main.async {
if image != nil {
weakSelf?.imgView.image = image
...
}
}
})
}

图片的获取是通过PHImageManager来获得,在这里遇到了一个坑,在网上普遍看到的写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DispatchQueue.global().async {
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .highQualityFormat
requestOptions.isSynchronous = true
//requestOptions.isNetworkAccessAllowed = true
weak var weakSelf = self
let manager = PHImageManager.default()
manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: requestOptions, resultHandler: { (image, dic) in
DispatchQueue.main.async {
if image != nil {
weakSelf?.imgView.image = image
weakSelf?.kXZFImage = image
}
}
})
}

代码中不包含requestOptions.isNetworkAccessAllowed = true此句代码,在模拟器上获取到了图片,但是在真机上调试的时候,打印出来的image = nil,很是纳闷,然后各种搜索查代码,然后把targetSize,给替换成了一个固定的值,结果打印出来的图片尺寸全部都是一样,并不是原图。最后又是各种尝试,查找资料,发现一篇文章里的代码包含这一句requestOptions.isNetworkAccessAllowed = true代码,然后再去尝试,发现获取原图成功了。应该是PHImageManager需要从Apple方获取原图。
如果想获取自定义的图片尺寸,就按照第一种写法,可以快速的获取到图片。如果想获取原图,就需要按照第二种写法,获取,把注释掉的代码释放出来,这样有一个问题就是,相册图片比较多,图片比较大的时候,加载会比较慢。

第一种写法的requestOptions.resizeMode有三个可选项

  • none // no resize 不重设size
  • fast // use targetSize as a hint for optimal decoding when the source image is a compressed format (i.e. subsampling), the delivered image may be larger than targetSize (当源图像是压缩格式(即次采样)时,使用Target Size作为最佳解码提示时,交付的图像可能大于Target Size)
  • exact // same as above but also guarantees the delivered image is exactly targetSize (must be set when a normalizedCropRect is specified) (与上面相同,但也保证交付的图像是准确的目标大小(必须在指定了规范化的CropRect时设置))

第二种写法的requestOptions.deliveryMode

  • opportunistic // client may get several image results when the call is asynchronous or will get one result when the call is synchronous (当调用是异步的时,客户端可能会得到多个映像结果,或者在调用是同步的时候会得到一个结果。)
  • highQualityFormat // client will get one result only and it will be as asked or better than asked (sync requests are automatically processed this way regardless of the specified mode)(客户端将只获得一个结果,并且它将被问到或者比被请求的结果更好(同步请求将以这种方式自动处理,而不管指定的模式如何)。)
  • fastFormat // client will get one result only and it may be degraded (客户端只会得到一个结果,并且可能会降级。)

具体的详解,可以看开篇提到的这篇blog,有系列的介绍。本次遇到的坑就是这些,记录一下,以防下次再踩。结尾,谢谢网上各位的分享,让知识传播起来。本文源码请戳这里

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 KNOWLEDGE IS POWER All Rights Reserved.

访客数 : | 访问量 :