Photo Kit 使用总结

ios访问系统相册的新框架Photo Kit在使用时候感觉还是蛮恶心的,所有总结了一下,整理下来,以备以后使用

请求相册授权

  • 在info.plist文件中加入下面两个key,一个是访问相册所需,另一个是调用摄像头所需

    NSPhotoLibraryUsageDescription
    访问相册
    NSCameraUsageDescription
    使用相机

  • 获取授权的状态
    鉴于ios对于用户隐私的保护,使用相册时需要用户授权,用户么有授权的时候不能访问相册,
PHPhotoLibrary 代表整个照片应用,权限的四种状态如下,
只有PHAuthorizationStatusAuthorized,才能使用相册

/*
PHAuthorizationStatusNotDetermined    未决定
PHAuthorizationStatusRestricted    受限制
PHAuthorizationStatusDenied    拒绝
PHAuthorizationStatusAuthorized    允许
*/

[PHPhotoLibrary authorizationStatus];

  • 如果用户没有开启授权,可以来个提醒,或者在合适的时机去跳转到授权界面
+(void)requestAuthorizationIfNotDetermined{
    
    if (IOSVersion >= 8.0) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
    } else {
        NSURL *privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"];
        if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) {
            [[UIApplication sharedApplication] openURL:privacyUrl];
        } else {
            
            UIAlertView *alert =  [[UIAlertView alloc]initWithTitle:@"相册未授权" message:@"请手动开启相册授权" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
            [alert show];
            
        }
    }
    
}



创建app对应的相册

先来了解几个类

PHAssetCollection

这个类相当于一个照片组,Collection就是集合的意思

属性

//The type of the asset collection, such as an album or a moment.
//相册的类型
@property(nonatomic, assign, readonly) PHAssetCollectionType assetCollectionType;

//子类型
@property(nonatomic, assign, readonly) PHAssetCollectionSubtype assetCollectionSubtype;

//估算的相册中的资源(Asset)数量,没什么卵用
@property(nonatomic, assign, readonly) NSUInteger estimatedAssetCount;

//开始日期
@property(nonatomic, strong, readonly) NSDate *startDate;
//结束日期
@property(nonatomic, strong, readonly) NSDate *endDate;

//粗略估计存放的位置,没什么卵用
@property(nonatomic, strong, readonly) CLLocation *approximateLocation;

//这个才是最有用的,这个就是所有相册名称的数组,
@property(nonatomic, strong, readonly) NSArray *localizedLocationNames;

//单个相册名称
@property(nonatomic, strong, readonly) NSString *localizedTitle;

这个框架里要查找某个东西,都是用 fetch xxx,这个规律
明显

  • 一些常用方法的解释
这个方法是我们传入一个相册名称的数组, PHFetchOptions,我们的一些描述信息
+ (PHFetchResult *)fetchAssetCollectionsWithLocalIdentifiers:(NSArray *)identifiers options:(PHFetchOptions *)options;
Photo Kit 使用总结_第1张图片
Snip20170815_1.png

PHFetchOptions

这个类就是对要要获取(Fetch)的内容的一个描述,相当于选择的条件整合,这个类就那么几个属性,可以根据需求来定义

属性

//描述信息, NSPredicate这个类和SQL语句的用法类似,具体可参见
http://www.cocoachina.com/ios/20160111/14926.html

@property(nonatomic, strong) NSPredicate *predicate;

//排序类型
用法如下,按照你要求的排序类型来给出查询结果
/*
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.sortDescriptors = @[
    [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES],
];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithOptions:fetchOptions];
return [fetchResult firstObject];
*/
@property(nonatomic, strong) NSArray *sortDescriptors;


//是否想要包含资源变化的详细信息
@property(nonatomic, assign) BOOL wantsIncrementalChangeDetails;


//每次的查询数量限制
@property(nonatomic, assign, readwrite) NSUInteger fetchLimit;

//这三个是要包含的资源类型
@property(nonatomic, assign) BOOL includeAllBurstAssets;
@property(nonatomic, assign) BOOL includeHiddenAssets;
@property(nonatomic, assign) PHAssetSourceType includeAssetSourceTypes;

下面开始创建对应app名称的一个相册


- (PHAssetCollection *)createdCollection
{
    // 获得软件名字
    NSString *title = [NSBundle mainBundle].infoDictionary[(__bridge NSString *)kCFBundleNameKey];
    
    // 抓取所有的自定义相册
    PHFetchResult *results= [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    
    // 查找当前App对应的自定义相册
    for (PHAssetCollection *collection in results) {
        if ([collection.localizedTitle isEqualToString:title]) {
            return collection;//找到了就返回
        }
    }
    
    /** 当前App对应的自定义相册没有被创建过 **/
    // 创建一个【自定义相册】
    NSError *error = nil;
    __block NSString *createdCollectionID = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        createdCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier;
    } error:&error];
    
    if (error) return nil;
    
    // 根据唯一标识获得刚才创建的相册
    return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionID] options:nil].firstObject;
}


系统相册的获取方法

自己封装了一个关于相册的类

#import 
#import "YSPhotoKit.h"

@interface YSAssetAlbum : NSObject

@property (nonatomic, strong) NSString *name;        ///< The album name
@property (nonatomic, assign) NSInteger count;       ///< Count of photos the album contain
@property (nonatomic, strong) PHFetchResult *result;       ///相当于存储asset的数组

@property (nonatomic, strong) NSArray *models;//所有照片模型
@property (nonatomic, strong) NSArray *selectedModels;//选中的照片
@property (nonatomic, assign) NSUInteger selectedCount;//选中的数量


+ (YSAssetAlbum *)albumWithResult:(PHFetchResult*)result name:(NSString *)name;


@end



//.m文件的实现

#import "YSAssetAlbum.h"

@implementation YSAssetAlbum

+ (YSAssetAlbum *)albumWithResult:(PHFetchResult*)result name:(NSString *)name{
    YSAssetAlbum *album = [[YSAssetAlbum alloc]init];
    album.result = result;
    album.name = name;
    
    if ([result isKindOfClass:[PHFetchResult class]]) {
        album.count = result.count;
    }
    
    return album;
}


@end




//获得相机胶卷
-(void)getSmartAlbumAllowVideo:(BOOL)allowVideo AllowPhoto:(BOOL)allowPhoto completion:(void(^)(YSAssetAlbum *model))completion{
    
    __block YSAssetAlbum *album ;

    PHFetchOptions *option = [[PHFetchOptions alloc]init];
    
    if (IOSVersion >= 8.0) {
        
        if (!allowVideo) {
            option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];

        }
        
        if (!allowPhoto) {
            option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
                                PHAssetMediaTypeVideo];
        }
        
        NSSortDescriptor *sortDescriptors = [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate];
        
        option.sortDescriptors = @[sortDescriptors];
        
        
        
        PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        
        for (PHAssetCollection *assetCollection in fetchResult) {
            
            //过滤掉不是相册的对象
            if (![assetCollection isKindOfClass:[PHAssetCollection class]]) {
                continue;
            }
            
            if ([self isCameraRollAlbum:assetCollection.localizedTitle]) {
                
                PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:option];
                
                album = [YSAssetAlbum albumWithResult:assetsFetchResult name:assetCollection.localizedTitle];
                
                if (completion){
                    completion(album);
                }
                
                break;
            }
            
        }
    
    }
    
}



总结

从上面的简单描述可见,查询一个相册内资源的方法是

1 首先要请求授权 PHPhotoLibrary
2 然后要创建描述信息 PHFetchOptions
3 然后用 PHAssetCollection 去fetch xxx ,得到PHFetchResult
4 接着遍历PHFetchResult,这个类里面存的又都是PHAssetCollection
5然后用 PHAsset 去fetch xxx ,获取资源得到的又是PHFetchResult *assetsFetchResult
这个PHFetchResult里面存的是PHAsset,其实PHFetchResult就是一个和数 组一样功能的类

  • 如果我们想要取得某个PHAsset所对应的照片或者视频,又需要用到一个类
    PHImageManager ,这个类是个单列,然后把我们的PHAsset当做参数传入这个类的 request xxxx ForAsset xxx方法中,类似的方法有好几个
    • requestImageForAsset
    • requestImageDataForAsset
    • requestLivePhotoForAsset
    • requestPlayerItemForVideo
    • requestAVAssetForVideo

[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeDefault options:option resultHandler:

最后查询的结果在resultHandler中回调出来,整个思路就是这样,我自己封装了一些方法,使用方便点,需要的可以去下载

https://github.com/HongXiuTanXiang/YSphoto

你可能感兴趣的:(Photo Kit 使用总结)