简介:
自从相机成为 iPhone 最重要和最受欢迎的功能开始,对能管理和加工用户照片库中宝贵的照片的应用程序和工具就有着巨大的需求。
在iOS设备中,照片和视频是相当重要的一部分,在前面的课程中,我们讲到了如何调用摄像头来实现拍照和录制视频,并将拍摄的照片或录制的视频保存到照片库,那么,我们如何访问相册获取拍摄的照片或视频呢?本节中,我们将学习如何访问相册并获取相册中的媒体资源文件。
1. UIImagePickerController访问相册
之前我们使用UIImagePickerController实现了拍照和视频录制,下面我们来介绍一下通过UIImagePickerController访问系统相册并获取相册里的图片。要用UIImagePickerController来访问相册选中相册中的图片通常可以分为如下步骤:
- 初始化UIImagePickerController的实例对象
- 指定数据源类型,注意:数据源类型不同看到的效果也是不同的
- 设置代理,实现选中结束的回调
- 展示UIImagePickerController(通常以模态窗口形式打开)
- 选中图片结束后再代理方法中获取图片并退出视图控制器
示例代码:
#import "ViewController.h"
@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@property (nonatomic, weak)IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 不要在viewDidLoad弹出相册控制器,否则会给出下面的警告
//whose view is not in the window hierarchy!
}
- (IBAction)showPhotosAlbum:(id)sender {
// 1. 初始化UIImagePickerController的实例对象
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// 2. 指定数据源类型
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
/*
UIImagePickerControllerSourceTypePhotoLibrary,// 所有媒体,进入相册的分组
UIImagePickerControllerSourceTypeCamera,// 访问相机,模拟器环境下不可选中
UIImagePickerControllerSourceTypeSavedPhotosAlbum// 进入图片相册moments(按时间做图片排序的相册)
*/
imagePicker.allowsEditing = YES;//允许图片编辑,选中图片后可以对图片做编辑操作
// 3. 设置代理,实现选中结束的回调
imagePicker.delegate = self;
// 注意,签署协议是需要同时声明UINavigationControllerDelegate,UIImagePickerControllerDelegate
// 4. 模态视图退出UIImagePickerController
[self presentViewController:imagePicker animated:YES completion:nil];
// 5. 选中图片结束后再代理方法中获取图片并退出视图控制器
}
#pragma mark - UIImagePickerControllerDelegate
// 设置允许编辑后选中完成回调该方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo {
NSLog(@"edit image and choose finished");
NSLog(@"editingInfo:%@",editingInfo);
/*
UIImagePickerControllerCropRect = "NSRect: {
{0, 0}, {3000, 2000}}";
UIImagePickerControllerEditedImage = "<UIImage: 0x7fa980d71460> size {1239, 825} orientation 0 scale 1.000000";
UIImagePickerControllerMediaType = "public.image";
UIImagePickerControllerOriginalImage = "<UIImage: 0x7fa983200860> size {3000, 2002} orientation 0 scale 1.000000";
UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED&ext=JPG";
*/
// 获取选中的媒体类型:public.image:图片 public.movie:视频
NSString *type = [editingInfo objectForKey:@"UIImagePickerControllerMediaType"];
if ([type isEqualToString:@"public.image"]) {
// 获取选中的媒体编辑图片
UIImage *image = [editingInfo objectForKey:UIImagePickerControllerEditedImage];
self.imageView.image = image;
}
// 退出相册界面
[picker dismissViewControllerAnimated:YES completion:nil];
}
// 选中完成
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
NSLog(@"choose finished");
NSLog(@"media info%@",info);
/*获取的媒体详情:
UIImagePickerControllerMediaType = "public.image";
UIImagePickerControllerOriginalImage = "<UIImage: 0x7fe248478c30> size {3000, 2002} orientation 0 scale 1.000000";
UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED&ext=JPG";
*/
// 获取选中的媒体类型:public.image:图片 public.movie:视频
NSString *type = [info objectForKey:@"UIImagePickerControllerMediaType"];
if ([type isEqualToString:@"public.image"]) {
// 获取选中的媒体原始图片
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
self.imageView.image = image;
}
// 退出相册界面
[picker dismissViewControllerAnimated:YES completion:nil];
}
// 取消选中
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
NSLog(@"choose cancel");
// 退出相册界面
[picker dismissViewControllerAnimated:YES completion:nil];
}
@end
2. Photos框架
事实上,在大多数应用中并不会直接在系统相册中获取图片,而是在一个自定义的界面,通常是UICollectionView中展示所有的相册图片,这需要我们遍历相册中所有的媒体对象。下面我们来看一下如何遍历相册中的媒体资源。
直到 2014 年夏天前,开发者只能用 AssetsLibrary 框架访问日益增长的用户的照片库。几年以来,相机应用和照片应用发生了显著的变化,增加了许多新特性,包括按时刻来组织照片的方式。但与此同时,AssetsLibrary框架却没有跟上步伐。鉴于ALAssetsLibrary的各种坑点,随着iOS8的到来,苹果给我们提供了一个现代化的框架 —— Photos,一个可以让应用更好地与设备照片库对接的框架。它比AssetsLibrary表现更好,并且拥有让应用和设备照片库无缝工作的特性。
Photos是一套比AssetsLibrary更完整也更高效的库,对资源的处理跟AssetsLibrary也有很大的不同,下面简单介绍Photos框架的基本构成:
- PHAsset : 代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源
- PHFetchOptions : 获取资源时的参数,可以传 nil,即使用系统默认值
- PHFetchResult : 表示一系列的资源集合,也可以是相册的集合
- PHAssetCollection : 表示一个相册或者一个时刻,或者是一个「智能相册(系统提供的特定的一系列相册,例如:最近删除,视频列表,收藏等等)
- PHImageManager : 用于处理资源的加载,加载图片的过程带有缓存处理,可以通过传入一个 PHImageRequestOptions 控制资源的输出尺寸等规格
PHImageRequestOptions : 如上面所说,控制加载图片时的一系列参数
这里还有一个额外的概念 PHCollectionList ,表示一组 PHCollection,它本身也是一个 PHCollection,因此 PHCollection 作为一个集合,可以包含其他集合,这使到Photos的组成比ALAssetLibrary 要复杂一些。另外与ALAssetLibrary相似,一个PHAsset可以同时属于多个不同的PHAssetCollection,最常见的例子就是刚刚拍摄的照片,至少同时属于“最近添加”、“相机胶卷”以及“照片-精选”这三个PHAssetCollection。关于这几个概念的关系如下图:
Photos框架获取资源
照片库中有两种资源可供获取:PHAsset和PHCollection,前者代表图像或视频对象,后者是前者的集合或自身类型的集合。PHCollection是个基类,有PHAssetCollection和PHCollectionList两个子类,分别代表 Photos 里的相册和文件夹。而PHCollectionList里可嵌套PHAssetCollection和自身类型,还支持多重嵌套。获取PHAsset以及PHAssetCollection的过程类似于 Core Data,如下所示,只能通过类方法来返回PHFetchResult,遍历返回的结果来获取需要的资源。
PHAsset Fetch Method