不要急,不要怕

PhotoKit

由于项目重构,将图片选择器重CTAssetsPickerController换成了TZImagePickerController,两者都是优秀的图片选择器,但我个人更喜欢后者(因为有中午说明~~)。

换完之后发现视频上传功能出问题了,原来以前的上传方法是用ALAssetsLibrary上传的,但是看TZImagePickerController发现8以后就使用的Photos Framework。

// If user picking a video, this handle will be called.
// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
// 如果用户选择了一个视频,下面的handle会被执行
// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset);

这是以前上传的两种方法,

ALAsset *asset = [mediaDatas objectAtIndexSafe:0];
NBLog(@"asset=%@, representation=%@, url=%@", asset, [asset defaultRepresentation], [asset defaultRepresentation].url);

 if (asset != nil) {

    if (/* DISABLES CODE */ (1)) {
        NSString *videoPath = [NSDocumentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.mov", 0]];    // 这里直接强制写一个即可,之前计划是用i++来区分不明视频
        //可以看出来使用fileURLWithPath创建出来的URL会自动加上协议头
        NSURL *url = [NSURL fileURLWithPath:videoPath];
        NSError *theErro = nil;
        BOOL exportResult = [asset exportDataToURL:url error:&theErro];
        NBLog(@"exportResult=%@", exportResult?@"YES":@"NO");

        NSData *videoData = [NSData dataWithContentsOfURL:url];
        //      NSData *videoData = [NSData dataWithContentsOfFile:videoPath];
        //                                        [formData appendPartWithFormData:videoData name:@"video1"];
        //第一个参数是服务器存你上传视频的文件夹名,第二个参数是你上传视频的名字,随便写。第三个是格式。
        [formData appendPartWithFileData:videoData name:@"video1" fileName:@"video1.mov" mimeType:@"video/quicktime"];

    }else {

        //第一种获取NSData的方式, 上传后, 后台仅获取到文本
        //ALAssetRepresentation获取本地相册
        ALAssetRepresentation *rep = [asset defaultRepresentation];
        Byte *buffer = (Byte*)malloc(rep.size);
        NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
        NSData *videoData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
        //传到服务器
        //[formData appendPartWithFormData:videoData name:@"video1"];
        [formData appendPartWithFileData:videoData name:@"video1" fileName:@"video1" mimeType:@"video/quicktime"];
     }

    NBLog(@"method 2");
}

点开ALAssetsLibrary,发现人性化的🍎早已为你写好了新方法
ALAssetsLibrary的方法
新方法:

PHAsset *asset = [mediaDatas objectAtIndexSafe:0];

 [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                         [formData appendPartWithFileData:imageData name:@"video1" fileName:@"video1" mimeType:@"video/quicktime"];
                   }];

由于现在项目最低8.0,所以就不做ALAssetsLibrary的方法的了。
好了,下面该说一说PHAsset了。


PHAsset:

PHAsset: 代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源
PHFetchOptions: 获取资源时的参数,可以传 nil,即使用系统默认值

//做选择的约束条件。比如,只获取图片,不获取视频。
 phopt.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];//只取图片

//按可指定字段用来对获取结果进行排序
phopt.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; // 按图片生成时间排序
phopt.includeHiddenAssets = YES;//获取结果是否包括被隐藏的资源
phopt.includeAllBurstAssets = YES;//获取结果是否包括连拍资源
phopt.wantsIncrementalChangeDetails = YES;//允许变化细节?

PHFetchResult: 表示一系列的资源集合,也可以是相册的集合,可以用类似 NSArray 的接口来访问PHFetchResult结果内的集合。

PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumAllHidden options:nil];

PHAssetCollection: 表示一个相册或者一个时刻,或者是一个「智能相册(系统提供的特定的一系列相册,例如:最近删除,视频列表,收藏等等),下面是一些只读属性

######assetCollectionType 资源集合类型,比如相册或者“时刻”相册,

enum PHAssetCollectionType : Int {

case Album //从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册
case SmartAlbum //经由相机得来的相册
case Moment //Photos 为我们自动生成的时间分组的相册

}

######assetCollectionSubtype 子类型

  enum PHAssetCollectionSubtype : Int {
case AlbumRegular //用户在 Photos 中创建的相册
case AlbumSyncedEvent //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
case AlbumSyncedFaces //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
case AlbumSyncedAlbum //做了 AlbumSyncedEvent 应该做的事
case AlbumImported //从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。
case AlbumMyPhotoStream //用户的 iCloud 照片流
case AlbumCloudShared //用户使用 iCloud 共享的相册
case SmartAlbumGeneric //文档解释为非特殊类型的相册,主要包括从 iPhoto 同步过来的相册。
case SmartAlbumPanoramas //相机拍摄的全景照片
case SmartAlbumVideos //相机拍摄的视频
case SmartAlbumFavorites //收藏文件夹
case SmartAlbumTimelapses //延时视频文件夹,同时也会出现在视频文件夹中
case SmartAlbumAllHidden //包含隐藏照片或视频的文件夹
case SmartAlbumRecentlyAdded //相机近期拍摄的照片或视频
case SmartAlbumBursts //连拍模式拍摄的照片
case SmartAlbumUserLibrary //这个命名最神奇了,就是相机相册,所有相机拍摄的照片或视频都会出现在该相册中,而且使用其他应用保存的照片也会出现在这里。
case Any //包含所有类型

}

######estimatedAssetCount :估算的asset数量,不精确

PHImageManager: 用于处理资源的加载,加载图片的过程带有缓存处理,可以通过传入一个 PHImageRequestOptions 控制资源的输出尺寸等规格,在框架中是个单例对象,用[PHImageManager defaultManager]获取,它提供了加载图片和视频的方法,

PHImageRequestOptions: 如上面所说,控制加载图片时的一系列参数

 PHImageRequestOptions  *options= [PHImageRequestOptions new];
 //这个属性是指获取的图像是否需要包含系统相册“编辑”功能处理过的信息(如滤镜,旋转等)
options.version = PHImageRequestOptionsVersionCurrent;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
/*
 PHImageRequestOptionsDeliveryModeOpportunistic = 0,图片获取速度和质量的平衡
 PHImageRequestOptionsDeliveryModeHighQualityFormat = 1,高质量图片,
 PHImageRequestOptionsDeliveryModeFastFormat = 2 快速得到图片的情况下保证质量
 */

options.resizeMode = PHImageRequestOptionsResizeModeExact;
/*
 PHImageRequestOptionsResizeModeNone = 0,不压缩
 PHImageRequestOptionsResizeModeFast,高效率请求,但是返回的图片尺寸可能和要求的尺寸不同
 PHImageRequestOptionsResizeModeExact,按照精准尺寸返回
 */

// 同步获得图片, 只会返回1张图片,PS: 若options.synchronous = YES,则不论options.deliveryMode如何设置,系统会选择PHImageRequestOptionsDeliveryModeHighQualityFormat(高质量图片)
options.synchronous = YES;
//是否联网获取iCloud的图片
options.networkAccessAllowed = NO;
//指定作物矩形单元坐标的原始图像,如的脸。默认为CGRectZero(不适用)
options.normalizedCropRect = CGRectMake(100, 200, 100, 100);

options.progressHandler
//一个 PHAssetImageProgressHandler 的 block,当从 iCloud 下载照片时,它就会被图像管理器自动调用还有一个与 iCloud 密切相关的属性当图像需要从 iCloud 下载时,这个 block 会被自动调用,block 中会返回图像下载的进度,图像的信息,出错信息。开发者可以利用这些信息反馈给用户当前图像的下载进度以及状况,但需要注意?progressHandler 不在主线程上执行,因此在其中需要操作 UI,则需要手工放到主线程执行。
options.progressHandler

更详细的戳这里

这个翻译也很直白

当然,还有PHImageCachingManager 用于处理图像的缓存这里就不说了~~
最后,挂个图:
PhotoKit构成