iOS8 Photos Framework

1. Model

PHAsset 、PHAssetCollection、PHCollectionList 是Photos框架中的模型類,PHAsset類是數(shù)據(jù)模型抬闯,描述圖片或者視頻文件數(shù)據(jù);PHAssetCollection描述了包括相冊影钉、moments画髓、智能相冊以及共享照片流等一系列圖片或者視頻文件的集合的元數(shù)據(jù);PHCollectionList是一組資源集合平委,可能是一組Assets奈虾,也可能是一組collection。 它們關(guān)系如下圖:

photos_model.png

1.1 PHAsset

PHAsset是iOS8平臺的新接口廉赔,存儲獲取圖片和視頻文件的元數(shù)據(jù)肉微,這些圖片和視頻文件可能在手機本地,也可能在iCloud蜡塌。相當(dāng)于以前的 ALAsset接口,但比起ALAsset,PhotoKit 提供了額外的關(guān)于用戶資源的元數(shù)據(jù)碉纳,而這些數(shù)據(jù)在以前使用 ALAssetsLibrary 框架中是沒有辦法訪問,或者很難訪問到馏艾。

它有幾個要點:
  • 需要用PHAsset的一些fetchAssets...系列類方法獲取到劳曹,你想要拿到的照片的PHAsset對象奴愉。
  • PHAsset 對象只包含元數(shù)據(jù),image或者video數(shù)據(jù)需要用PHImageManager加載铁孵。
  • PHAsset對象的元數(shù)據(jù)是不可變的锭硼,修改元數(shù)據(jù)需要借助 PHAssetChangeRequest
它有幾個重要屬性:
  • mediaType :資源類型,圖片或者音頻或視頻
    Paste_Image.png
  • mediaSubtypes:圖片又包含全景圖(Panorama)、HDR圖片蜕劝、屏幕截圖檀头、livePhoto .live photo 加3Dtouch效果太贊! [視頻鏈接].我們可以使用照片資源的 mediaSubtypes 屬性驗證資源庫中的圖像在捕捉時是否開啟了 HDR岖沛,拍攝時是否使用了相機應(yīng)用的全景模式.(http://www.macworld.com/article/2988585/apple-phone/how-to-get-started-with-3d-touch-live-photos-and-4k-video-on-the-iphone-6s.html)
    Paste_Image.png
  • Creation date
  • Location
  • Favorite 布爾值暑始,用戶是否標(biāo)記資源為"收藏",我們平時瀏覽照片或視頻婴削,在下方點??就表示收藏這張圖廊镜。
  • hidden 要驗證一個資源是否被用戶標(biāo)記為收被隱藏,只要檢查 PHAsset 實例的 hidden 屬性即可馆蠕。
  • sourceType : 資源可以來源自用戶相冊期升、iCloud惊奇、iTunes同步
    Paste_Image.png
  • representsBurstburstSelectionTypes: 對于一個資源互躬,如果其 PHAsset 的 representsBurst 屬性為 true,則表示這個資源是一系列連拍照片中的代表照片 (多張照片是在用戶按住快門時拍攝的)颂郎。它還有一個屬性是 burstIdentifier吼渡,如果想要獲取連拍照片中的剩余的其他照片,可以通過將這個值傳入 fetchAssetsWithBurstIdentifier(...) 方法來獲取乓序。用戶可以在連拍的照片中做標(biāo)記寺酪;此外,系統(tǒng)也會自動用各種試探來標(biāo)記用戶可能會選擇的潛在代表照片替劈。這個元數(shù)據(jù)是可以通過 PHAsset 的 burstSelectionTypes 屬性來訪問寄雀。這個屬性是用三個常量組成的位掩碼:.UserPick 表示用戶手動標(biāo)記的資源,.AutoPick 表示用戶可能標(biāo)記的潛在資源陨献,.None 表示沒有標(biāo)記的資源盒犹。
Paste_Image.png

我模擬器相冊中某張圖片:

<PHAsset: 0x7f8293659e20> B84E8479-475C-4727-A4A4-B77AA9980897/L0/001 mediaType=1/0, sourceType=1, (4288x2848), creationDate=2009-10-09 21:09:20 +0000, location=0, hidden=0, favorite=0 

localIdentifier

Photos 框架中的根類PHObject只有一個公開接口localIdentifier,是對象唯一唯一標(biāo)志符.PHObject實現(xiàn)了-isEqual 和-hash方法.可以直接使用localIdentifier屬性對PHObject及其子類對象進行對比是否同一個對象种柑。

在我的模擬器中“最近刪除”這個相冊的localIdentifier為72053882-BF20-4D4A-B1A5-03D1DDAE1707/L0/040

1.2 PHAssetCollection

PHAssetCollection是一組有序的資源集合,包括相冊痪蝇、moments、智能相冊以及共享照片流.
它的重要屬性 辆飘;

  • assetCollectionType 資源集合類型龄捡,比如相冊或者“時刻”相冊
typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
   PHAssetCollectionTypeAlbum      = 1,
   PHAssetCollectionTypeSmartAlbum = 2,
   PHAssetCollectionTypeMoment     = 3,
} NS_ENUM_AVAILABLE_IOS(8_0);
  • assetCollectionSubtype 子類型
enum PHAssetCollectionType : Int {
    case Album //從 iTunes 同步來的相冊卓嫂,以及用戶在 Photos 中自己建立的相冊
    case SmartAlbum //經(jīng)由相機得來的相冊
    case Moment //Photos 為我們自動生成的時間分組的相冊
}

enum PHAssetCollectionSubtype : Int {
    case AlbumRegular //用戶在 Photos 中創(chuàng)建的相冊
    case AlbumSyncedEvent //使用 iTunes 從 Photos 照片庫或者 iPhoto 照片庫同步過來的事件。然而聘殖,在iTunes 12 以及iOS 9.0 beta4上晨雳,選用該類型沒法獲取同步的事件相冊行瑞,而必須使用AlbumSyncedAlbum。
    case AlbumSyncedFaces //使用 iTunes 從 Photos 照片庫或者 iPhoto 照片庫同步的人物相冊餐禁。
    case AlbumSyncedAlbum //做了 AlbumSyncedEvent 應(yīng)該做的事
    case AlbumImported //從相機或是外部存儲導(dǎo)入的相冊蘑辑,完全沒有這方面的使用經(jīng)驗,沒法驗證坠宴。
    case AlbumMyPhotoStream //用戶的 iCloud 照片流
    case AlbumCloudShared //用戶使用 iCloud 共享的相冊
    case SmartAlbumGeneric //文檔解釋為非特殊類型的相冊洋魂,主要包括從 iPhoto 同步過來的相冊。
    case SmartAlbumPanoramas //相機拍攝的全景照片
    case SmartAlbumVideos //相機拍攝的視頻
    case SmartAlbumFavorites //收藏文件夾
    case SmartAlbumTimelapses //延時視頻文件夾喜鼓,同時也會出現(xiàn)在視頻文件夾中
    case SmartAlbumAllHidden //包含隱藏照片或視頻的文件夾
    case SmartAlbumRecentlyAdded //相機近期拍攝的照片或視頻
    case SmartAlbumBursts //連拍模式拍攝的照片    
    case SmartAlbumUserLibrary //這個命名最神奇了副砍,就是相機相冊,所有相機拍攝的照片或視頻都會出現(xiàn)在該相冊中庄岖,而且使用其他應(yīng)用保存的照片也會出現(xiàn)在這里豁翎。
    case Any //包含所有類型
}
  • startDate

  • endDate

  • estimatedAssetCount :估算的asset數(shù)量,不精確
    我模擬器 智能相冊里隅忿,“最近刪除”這個相冊的對象信息

<PHAssetCollection: 0x7f82951bd640> 72053882-BF20-4D4A-B1A5-03D1DDAE1707/L0/040 Recently Deleted assetCollectionType=2/1000000201

1.3 PHCollectionList

一組有序的資源集合的集合心剥,暫時還沒用過。幾個重要屬性:

  • collectionListType
  • collectionListSubtype
  • startDate
  • endDate

2. 獲取模型數(shù)據(jù)

PHAsset 背桐、PHCollection优烧、PHCollectionList有一系列類方法可供我們訪問資源的元數(shù)據(jù)

2.1 比如PHAsset提供了一系列獲取PHAsset對象的方法

+ fetchAssetsInAssetCollection:options:
+ fetchAssetsWithMediaType:options:
+ fetchAssetsWithLocalIdentifiers:options:
+ fetchKeyAssetsInAssetCollection:options:
+ fetchAssetsWithOptions:
+ fetchAssetsWithBurstIdentifier:options:
+ fetchAssetsWithALAssetURLs:options:

其中fetchAssetsInAssetCollection:options:方法可以獲取資源集合中的所有asset對象。每個方法中的 PHFetchOptions參數(shù)链峭,是獲取asset對象的一些配置畦娄,我們可以設(shè)置獲取asset的條件,比如獲取哪種資源,如何分類弊仪。獲取的時候熙卡,如果該參數(shù)為空,則使用系統(tǒng)的默認(rèn)值励饵,當(dāng)我們調(diào)用如上所示方法獲取時驳癌,可以直接傳nil。

例子:

    PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
    // 按圖片生成時間排序
    allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    // 獲取圖片
    PHFetchResult *allPhotos = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
    // 獲取智能相冊
    PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    // 獲取用戶創(chuàng)建的相冊
    PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];

2.2 PHFetchOptions

  • predicate : 做選擇的約束條件役听。比如颓鲜,只獲取圖片,不獲取視頻禾嫉。指定 PHAssetMediaType為image.

    //  swift:
    

options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue)
```

  • sortDescriptors 可指定字段用來對獲取結(jié)果進行排序
  • includeHiddenAssets 獲取結(jié)果是否包括被隱藏的資源
  • includeAllBurstAssets 獲取結(jié)果是否包括連拍資源
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.wantsIncrementalChangeDetails = YES;
options.includeAllBurstAssets = YES;
options.includeHiddenAssets = YES;
// 只取圖片
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];
// 按時間排序
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

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

2.3 PHFetchResult

類似數(shù)組灾杰,存儲獲取到asset對象集合。

  • 同步快速獲取結(jié)果,
  • 即使結(jié)果集很大熙参,框架也能保證獲取速度. 因為它不會一次性將所有結(jié)果放進內(nèi)存艳吠,而是按需批量加載
  • 可以用類似 NSArray 的接口來訪問PHFetchResult結(jié)果內(nèi)的集合。
    比如 :
        PHCollection *collection = smartAlbums[n];        

3. 資源對象的增刪改

上面PHAsset PHAssetCollection PHCollectionList對象都是不可變的孽椰。那么我們?nèi)绾螌崿F(xiàn)資源增刪改呢昭娩?要借助 request API :

request.png

比如:這段代碼用來修改一張圖片的資源屬性:是否被收藏凛篙。

  // 創(chuàng)建
  request = [PHAssetChangeRequest creationRequestForAssetFromImage:image]
 
- (void)toggleFavoriteForAsset:(PHAsset *)asset {
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // 改變
        PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset];
        request.favorite = !asset.favorite;
          } completionHandler:^(BOOL success, NSError *error) {
        NSLog(@"Finished updating asset. %@", (success ? @"Success." : error));
    }];
}

(1) 創(chuàng)建PHAssetChangeRequest對象。想要修改資源栏渺,需要創(chuàng)建一個 PHAssetChangeRequest 呛梆。然后你就可以修改創(chuàng)建創(chuàng)建日期,資源位置磕诊,以及是否將隱藏資源填物,是否將資源看做用戶收藏等。此外霎终,你還可以從用戶的庫里刪除資源滞磺。類似地,若要修改資源集合或集合列表莱褒,需要創(chuàng)建一個 PHAssetCollectionChangeRequestPHCollectionListChangeRequest對象击困。然后你就可以修改集合標(biāo)題,添加或刪除集合成員广凸,或者完全刪除集合阅茶。
(2) 操作的請求都要求在PHPhotoLibrary的performChanges的changeBlock中執(zhí)行
(3)如果有更新UI操作,需要遵守PHPhotoLibraryChangeObserver協(xié)議,實現(xiàn)photoLibraryDidChange(changeInfo: PHChange!)方法.在photoLibraryDidChange中進行UI更新操作谅海。

比如脸哀,下面2段代碼用來向冊中新增一張圖片:

    // 為image對象生成PHAsset對象,并加入collection
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        
        if (self.assetCollection) {
            PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
            [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
        }
    } completionHandler:^(BOOL success, NSError *error) {
        if (!success) {
            NSLog(@"Error creating asset: %@", error);
        }
    }];

創(chuàng)建一個新資源只要用 creationRequestForAssetFromXXX(...)
工廠方法胁赢,來創(chuàng)建變化請求企蹭,并傳入資源圖像數(shù)據(jù) (或一個 URL)白筹。如果你需要對新建的資源做額外的修改智末,你可以用創(chuàng)建變化請求的placeholderForCreatedAsset屬性。它會返回一個可用的 placeholder 來代替“真實的” PHAsset 引用.

// PHPhotoLibraryChangeObserver協(xié)議的方法徒河,更新相冊UI
- (void)photoLibraryDidChange:(PHChange *)changeInstance {
    // Check if there are changes to the assets we are showing.
    PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResults];
    if (collectionChanges == nil) {
        return;
    }
    
    /*
        Change notifications may be made on a background queue. Re-dispatch to the
        main queue before acting on the change as we'll be updating the UI.
     */
    dispatch_async(dispatch_get_main_queue(), ^{
        // Get the new fetch result.
        self.assetsFetchResults = [collectionChanges fetchResultAfterChanges];
        
        UICollectionView *collectionView = self.collectionView;
        
        if (![collectionChanges hasIncrementalChanges] || [collectionChanges hasMoves]) {
            // Reload the collection view if the incremental diffs are not available
            [collectionView reloadData];
            
        } else {
            /*
                Tell the collection view to animate insertions and deletions if we
                have incremental diffs.
             */
            [collectionView performBatchUpdates:^{
                NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
                if ([removedIndexes count] > 0) {
                    [collectionView deleteItemsAtIndexPaths:[removedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                }
                
                NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
                if ([insertedIndexes count] > 0) {
                    [collectionView insertItemsAtIndexPaths:[insertedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                }
                
                NSIndexSet *changedIndexes = [collectionChanges changedIndexes];
                if ([changedIndexes count] > 0) {
                    [collectionView reloadItemsAtIndexPaths:[changedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                }
            } completion:NULL];
        }
        
        [self resetCachedAssets];
    });
}

3.1 PHPhotoLibrary

系統(tǒng)中PHPhotoLibrary單例對象 是用來維護用戶照片庫系馆。當(dāng)我們需要編輯資源對象元數(shù)據(jù)、資源內(nèi)容顽照、或者插入新的資源對象等由蘑,都可以借助通過PHPhotoLibrary單例對象執(zhí)行block,block中創(chuàng)建我們指定的請求對象(比如PHAssetChangeRequest,PHAssetCollectionChangeRequest, PHCollectionListChangeRequest的對象)代兵。photoLibraryDidChange(changeInfo: PHChange!)中進行.

3.2 協(xié)議PHPhotoLibraryChangeObserver

PHPhotoLibraryChangeObserver協(xié)議能讓我們知道照片相冊庫中的改變尼酿。Photos會發(fā)送系統(tǒng)圖片改變的消息,我們可以遵守PHPhotoLibraryChangeObserver協(xié)議植影,并通過 PHPhotoLibrary的registerChangeObserver方法將對象注冊為觀察者裳擎,時時接收照片改變的消息。

3.3 PHChange

PHphoto框架會提供給我們PHChange對象思币,我們可以調(diào)用changeDetailsForObject或者changeDetailsForFetchResult 方法鹿响,它返回給我們一個PHObjectChangeDetails對象羡微,是對最新的照片實體對象的引用,可以告訴我們對象的圖像數(shù)據(jù)是否曾變化過惶我、對象是否曾被刪除過妈倔。

4.請求圖片和視頻數(shù)據(jù)

4.1 PHImageManager

PHImageManager在框架中是個單例對象,用[PHImageManager defaultManager]獲取,它提供了加載圖片和視頻的方法绸贡。
比如:圖像請求是通過 requestImageForAsset(...) 方法派發(fā)的盯蝴。
這些方法的參數(shù):

  • 一個 PHAsset對象,
  • PHImageRequestOptions 參數(shù)對象:可以設(shè)置返回圖像的大小和圖像的其它可選項
  • 結(jié)果回調(diào) (result handler)听怕。
請求圖片
- requestImageForAsset:targetSize:contentMode:options:resultHandler:
- requestImageDataForAsset:options:resultHandler:
請求視頻
- requestPlayerItemForVideo:options:resultHandler:
- requestExportSessionForVideo:options:exportPreset:resultHandler:
- requestAVAssetForVideo:options:resultHandler:

默認(rèn)情況下结洼,這些API是異步執(zhí)行,但是我們可以通過options參數(shù)中的synchronous屬性叉跛,設(shè)置為同步執(zhí)行松忍,這些方法會阻塞當(dāng)前調(diào)用線程直到下載完成或者發(fā)生錯誤。

4.2 請求圖片

//加載 160X160 像素的圖片
[manager requestImageForAsset:photo
                   targetSize:CGSizeMake(160,160)
                  contentMode:PHImageContentModeAspectFill
                      options:nil
                resultHandler:^(UIImage *result, NSDictionary *info) {
    if (result) {
        [cell setImage:result];
    } else {
... }
}];

targetSize: 返回圖片的尺寸

contentMode :決定了照片應(yīng)該以按比例縮放還是按比例填充的方式放到目標(biāo)大小內(nèi)筷厘。

options: PHImageRequestOptions類用于定制請求鸣峭。上面的方法返回指定尺寸的圖像,如果你僅僅指定必要的參數(shù)而沒有對 options 進行配置的話酥艳,返回的圖像尺寸將會是原始圖像的尺寸摊溶。或者充石,你指定的尺寸很小莫换,這時候會按照你的要求來返回接近該尺寸的圖像。

4.2.1 PHImageRequestOptions有以下幾個重要的屬性:

synchronous: 指定請求是否同步執(zhí)行骤铃。

resizeMode: 對請求的圖像怎樣縮放拉岁。有三種選擇:None,不縮放惰爬;Fast喊暖,盡快地提供接近或稍微大于要求的尺寸;Exact撕瞧,精準(zhǔn)提供要求的尺寸陵叽。

deliveryMode: 圖像質(zhì)量。有三種值:Opportunistic丛版,在速度與質(zhì)量中均衡巩掺;HighQualityFormat,不管花費多長時間页畦,提供高質(zhì)量圖像胖替;FastFormat,以最快速度提供好的質(zhì)量。

normalizedCropRect: 用于對原始尺寸的圖像進行裁剪刊殉,基于比例坐標(biāo)殉摔。只在 resizeMode 為 Exact 時有效。

resizeMode 默認(rèn)是 None记焊,這也造成了返回圖像尺寸與要求尺寸不符逸月。這點需要注意。要返回一個指定尺寸的圖像需要避免兩層陷阱:一定要指定 options 參數(shù)遍膜,resizeMode 不能為 None碗硬。

PHImageManager.png

是否裁剪圖片由 targetSize、contentMode來控制瓢颅,裁剪的尺寸由targetSize恩尾、contentMode、resizeMode指定挽懦。

比如

// 下載原圖:
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeExact;
options.progressHandler = (PHAssetImageProgressHandler)progress;
targetSize = PHImageManagerMaximumSize;
contentMode = PHImageContentModeDefault;

// 全屏圖
 options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.resizeMode = PHImageRequestOptionsResizeModeExact;
options.progressHandler = (PHAssetImageProgressHandler)progress;
targetSize = UIScreen.mainScreen.bounds.size;
contentMode = PHImageContentModeAspectFit;

4.2.2 resultHandler可能被多次調(diào)用

見上圖翰意,

  • 如果synchronous屬性為YES,同步請求信柿,resultHandler只會執(zhí)行一次冀偶,并且返回高質(zhì)量的圖片。
Paste_Image.png
  • 但是如果synchronous為NO渔嚷,resultHandler是否會被多次調(diào)用取決于deliveryMode屬性:
    • 如果deliveryMode是.HighQualityFormat 进鸠,resultHandler調(diào)用一次,框架只返回高質(zhì)量圖形病。
    • 如果deliveryMode是FastFormat客年,resultHandler也只被調(diào)用一次,保證速度盡可能保證圖片質(zhì)量漠吻。
    • deliveryMode是.Opportunistic Photos 可能會先提供低質(zhì)量的圖像以供臨時顯示量瓜,隨后會將指定尺寸的圖像返回。如果指定尺寸的高質(zhì)量的圖像有緩存侥猩,那么直接提供高質(zhì)量的圖像榔至。如圖,第一次同步調(diào)用請求返回一張模糊的圖,第二次再去下載一張高質(zhì)量的圖片:
result_handler.png

resultHandler中的info 字典提供了關(guān)于當(dāng)前請求狀態(tài)的信息欺劳,比如:

  • 圖像是否必須從 iCloud 請求 (如果你初始化時將 networkAccessAllowed 設(shè)置成 false,那么就必須重新請求圖像) —— PHImageResultIsInCloudKey 铅鲤。
  • 當(dāng)前遞送的 UIImage 是否是最終結(jié)果的低質(zhì)量格式划提。當(dāng)高質(zhì)量圖像正在下載時,這個可以讓你給用戶先展示一個預(yù)覽圖像 —— PHImageResultIsDegradedKey邢享。
  • 請求 ID (可以便捷的取消請求)鹏往,以及請求是否已經(jīng)被取消。 —— PHImageResultRequestIDKey 和 PHImageCancelledKey骇塘。
    如果沒有圖像提供給 result handler伊履,字典內(nèi)還會有一個錯誤信息 —— PHImageErrorKey韩容。

比如用-requestImageForAsset:targetSize:contentMode:options:resultHandler:接口請求圖片

// 入?yún)ⅲ簐ideo對應(yīng)的PHAsset對象
// info字典返回:
"PHImageResultRequestIDKey" : (int)1 
"PHImageResultImageTypeKey" : (long)0 
"PHImageResultDeliveredImageFormatKey" : (long)5005 
"PHImageResultIsDegradedKey" : @"0" 
注: 返回的image是video第一幀的截圖

// 入?yún)ⅲ簣D片對應(yīng)的PHAsset對象
// info字典返回:
"PHImageFileOrientationKey" : (long)0 
"PHImageResultWantedImageFormatKey" : (long)5005 
"PHImageResultRequestIDKey" : (int)2 
"PHImageResultDeliveredImageFormatKey" : (long)4031 
"PHImageResultIsDegradedKey" : @"1" 

4.3 請求視頻

// 視頻請求對象 
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
// 最高質(zhì)量的視頻
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
// 可從iCloud中獲取圖片
options.networkAccessAllowed = YES;
// 如果是iCloud的視頻,可以獲取到下載進度
options.progressHandler = ^(double progress, NSError *error, BOOL *stop) {
    [self updateUserVisibleProgress:progress error:error];
         // 此回調(diào)block可能不在UI線程中唐瀑,我們需要在UI線程中更新UI     
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressView.progress = progress;
        });

};
// 方法1
[manager requestPlayerItemForVideo:video options:options resultHandler:....]
// 方法2
[manager requestExportSessionForVideo:video options:options ...];
// 方法3
[manager requestAVAssetForVideo:video options:options resultHandler...];

5. 滾動性能:緩存

5.1 PHCachingImageManager

滾動一系列縮略圖時群凶,我們可以在可視區(qū)域前后維護一些數(shù)據(jù)緩存。如圖:


cache.png
  1. 生成PHCachingImageManager實例
  2. 調(diào)用方法startCachingImagesForAssets:targetSize:contentMode:options:哄辣,并指定 目標(biāo)尺寸target size请梢,內(nèi)容模式content mode,選項options參數(shù)
  3. 需要從asset對象中獲取圖片的時候力穗,調(diào)用
    requestImageForAsset:targetSize:contentMode:options:resultHandler

PHCachingImageManager *cim =  [[PHCachingImageManager alloc] init];
NSArray *soonToBeVisibleAssets = [cim startCachingImagesForAssets:soonToBeVisibleAssets
                                            targetSize:targetSize
                                         contentMode:PHImageContentModeAspectFill
                                                    options:nil];
NSArray *previouslyVisibleAssets = [cim stopCachingImagesForAssets:previouslyVisibleAssets
                                                        targetSize:targetSize
                                                         contentMode:PHImageContentModeAspectFill
                                                            options:nil];

// 從緩存中讀取相片

  // Request an image for the asset from the PHCachingImageManager.
    [self.imageManager requestImageForAsset:asset
         targetSize:AssetGridThumbnailSize
        contentMode:PHImageContentModeAspectFill
         options:nil
         resultHandler:^(UIImage *result, NSDictionary *info) {
        // Set the cell's thumbnail image if it's still showing the same asset.
        if ([cell.representedAssetIdentifier isEqualToString:asset.localIdentifier]) {
            cell.thumbnailImage = result;
        }
    }];

官方demo中計算緩存區(qū)域的算法比較有意思

- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler {
    if (CGRectIntersectsRect(newRect, oldRect)) {
        CGFloat oldMaxY = CGRectGetMaxY(oldRect);
        CGFloat oldMinY = CGRectGetMinY(oldRect);
        CGFloat newMaxY = CGRectGetMaxY(newRect);
        CGFloat newMinY = CGRectGetMinY(newRect);
        
        if (newMaxY > oldMaxY) {
            CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
            addedHandler(rectToAdd);
        }
        
        if (oldMinY > newMinY) {
            CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
            addedHandler(rectToAdd);
        }
        
        if (newMaxY < oldMaxY) {
            CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
            removedHandler(rectToRemove);
        }
        
        if (oldMinY < newMinY) {
            CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
            removedHandler(rectToRemove);
        }
    } else {
        addedHandler(newRect);
        removedHandler(oldRect);
    }
}

參考

WWDC

官方例子

Photos 框架實踐以及坑

照片框架

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毅弧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子当窗,更是在濱河造成了極大的恐慌够坐,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崖面,死亡現(xiàn)場離奇詭異咆霜,居然都是意外死亡,警方通過查閱死者的電腦和手機嘶朱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門蛾坯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疏遏,你說我怎么就攤上這事脉课。” “怎么了财异?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵倘零,是天一觀的道長。 經(jīng)常有香客問我戳寸,道長呈驶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任疫鹊,我火速辦了婚禮袖瞻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拆吆。我一直安慰自己聋迎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布枣耀。 她就那樣靜靜地躺著霉晕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牺堰,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天拄轻,我揣著相機與錄音,去河邊找鬼伟葫。 笑死恨搓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扒俯。 我是一名探鬼主播奶卓,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撼玄!你這毒婦竟也來了夺姑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤掌猛,失蹤者是張志新(化名)和其女友劉穎盏浙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荔茬,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡废膘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了慕蔚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丐黄。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖孔飒,靈堂內(nèi)的尸體忽然破棺而出灌闺,到底是詐尸還是另有隱情,我是刑警寧澤坏瞄,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布桂对,位于F島的核電站,受9級特大地震影響鸠匀,放射性物質(zhì)發(fā)生泄漏蕉斜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一缀棍、第九天 我趴在偏房一處隱蔽的房頂上張望宅此。 院中可真熱鬧,春花似錦睦柴、人聲如沸诽凌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春狱窘,著一層夾襖步出監(jiān)牢的瞬間杜顺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工蘸炸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躬络,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓搭儒,卻偏偏與公主長得像穷当,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淹禾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容