Photo Kit Tips

iOS8出現(xiàn)了Photo Kit,相信很多同學(xué)早已開始使用.隨著iOS11的到來,對于大部分App來說,iOS7應(yīng)該漸漸的退出歷史舞臺.如果想要重構(gòu)代碼,相信相冊是一個優(yōu)先級較高的模塊.

如何使用Photo Kit,有太多的資料,這里就不在贅述.這里提供一些tips,記錄下一些需要注意的地方.

API版本

注意API的版本.雖然Photo Kit是iOS8的產(chǎn)物,但是仍然由部分API是出現(xiàn)在iOS9上.例如PHFetchOptionsfetchLimit.

API特性差異

API也在不同的iOS版本中迭代.其中造成了特性的差異.例如在獲取圖片的exif信息時,我們通常使用一條API:

- (PHContentEditingInputRequestID)requestContentEditingInputWithOptions:(nullable PHContentEditingInputRequestOptions *)options completionHandler:(void (^)(PHContentEditingInput *__nullable contentEditingInput, NSDictionary *info))completionHandler PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);

在回調(diào)中,返回一個PHContentEditingInput,我們可以根據(jù)其fullSizeImageURL屬性創(chuàng)建一個CIImage,CIImageproperties即為exif信息.

但是這條API在iOS10和10以前是有差異的.根據(jù)文檔描述:

In iOS 10.0, tvOS 10.0, and later, Photos always calls this block on the main
queue. In earlier releases, Photos calls this block on an arbitrary serial queue
—if your block needs to update the UI, dispatch that work to the main queue.

所以會引申出一個問題:
在兼容iOS7的時代,我們通常使用ALAssetmetaData作為exif信息.這是同步的.但如果切換成Photo kit,取exif信息則是異步的.并且該API并沒有同步選項.那么此時有2種選擇:

  1. 修改代碼邏輯,切換成異步.
  2. 修改獲取exif方法為同步.

如果選擇方案1,那么OK.沒有任何影響.如果采用方案2,那么通常采用dispatch_semaphore_t來進行處理.

事實上,如此處理的話,在iOS10以前都是OK的.但是iOS10以及以后會出現(xiàn)死鎖的現(xiàn)象.至于原因,也就是API的描述了.iOS10會主動切換到主線程.那為毛切換到主線程就會死鎖?這可以去詳細(xì)了解下GCD的原理啦!

所以..還是選擇方案1吧..

變更處理

變更處理算是相冊相關(guān)處理比價復(fù)雜的一個地方.

Photo Kit處理的看似很復(fù)雜,有很多個很奇怪的東西.例如:PHChange,PHFetchResultChangeDetails等.

但是仔細(xì)看看,實際上是非常容易理解的.

需要注意的是文檔的一些說明:

when updating your app’s interface, apply removals before insertions, changes,
and moves

這里提醒了處理順序.

然后變更可能會多次調(diào)用,即使你僅僅刪除了一張照片或者增加一張照片.多次調(diào)用的原因是changed變更這個東東.可能系統(tǒng)會認(rèn)為你更新了某些照片.

所以合理的刷新策略是關(guān)鍵.如果收到了變更通知就刷新相關(guān)列表,可能會造成性能的浪費.

最后一個是,一般來講,照片的順序是依據(jù)創(chuàng)建時間或者修改時間.所以通常在處理insert變更的時候,無論修改時間還是創(chuàng)建時間,都是最新的.那么可能直接就插入到照片數(shù)組的0的index了.

實際上還要考慮到用戶可能修改了時間,照片中存在著未來時間這樣一種情況.

exif

ALLibrary中,提供了一條api:

- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef metadata:(NSDictionary *)metadata completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock NS_DEPRECATED_IOS(4_1, 9_0, "Use creationRequestForAssetFromImage: on PHAssetChangeRequest from the Photos framework to create a new asset instead");

這條api可以連同圖片和exif信息一起寫入.

而Photo Kit并沒有提供類似的方法.那么需要自己處理.

可以這樣將exif信息寫入image:

- (NSData *)appendExif:(NSDictionary *)exif toImage:(UIImage *)image {
    NSData *data = UIImageJPEGRepresentation(image, 1);
    CFDataRef cfData = CFBridgingRetain(data);
    CGImageSourceRef imageSource = CGImageSourceCreateWithData(cfData, nil);
    CFBridgingRelease(cfData);
    NSDictionary *defaultAttributes = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
    NSMutableDictionary *attributes = defaultAttributes.mutableCopy;
    [attributes addEntriesFromDictionary:exif];
    
    NSMutableData *output = [NSMutableData new];
    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)output, kUTTypeJPEG, 1, NULL);
    CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, (__bridge CFDictionaryRef)attributes);
    CGImageDestinationFinalize(imageDestination);
    CFRelease(imageDestination);
    return output;
}

但是這返回的是NSData,如果直接轉(zhuǎn)換成UIImage,那么相關(guān)的exif信息將會丟失.
所以需要做的是,將這個data寫入到文件.然后使用以下方法創(chuàng)建request,最終保存.

PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
照片

Photo Kit中取照片需要傳入一個size.并沒有ALAsset中的thumb等內(nèi)置尺寸.不過可以簡單的實驗出對應(yīng)的size.

而這里的size是絕對size(像素).例如:size傳入(100,100),那么無論在何種屏幕上,都是100*100的尺寸.有可能會在plus這種3x的屏幕上造成模糊.

所以更合理的做法是size乘以一個scale:

[UIScreen mainScreen].scale
緩存

官方提供了一個PHCachingImageManager用于緩存.方法很簡單,只有一個start,兩個stop方法.

蘋果也提供了一個在scrollview中使用緩存的算法.核心思路是:

根據(jù)當(dāng)前位置,計算出一個更大的區(qū)域.將更大的區(qū)域中的cell/collectionView cell的index path計算出來.然后緩存這個更大的區(qū)域中的數(shù)據(jù).當(dāng)然,也會計算區(qū)域的差值,用于取消緩存.

類似于一個預(yù)加載+緩存的思路.

不過對于快速滑動的列表,預(yù)加載對于加載速度的提升起不了太大的作用.只有緩存是有用的.如果想要提升加載速度(非緩存).適當(dāng)?shù)臏p少獲取圖片的size是一個效果提升比較明顯的途徑.甚至可以針對中低端機型進行處理.合理的策略,能夠做到更好的用戶體驗.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炼蛤,一起剝皮案震驚了整個濱河市妖爷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌理朋,老刑警劉巖絮识,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嗽上,居然都是意外死亡次舌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門兽愤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彼念,“玉大人,你說我怎么就攤上這事浅萧」矗” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵惯殊,是天一觀的道長。 經(jīng)常有香客問我也殖,道長土思,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任忆嗜,我火速辦了婚禮己儒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捆毫。我一直安慰自己闪湾,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布绩卤。 她就那樣靜靜地躺著途样,像睡著了一般。 火紅的嫁衣襯著肌膚如雪濒憋。 梳的紋絲不亂的頭發(fā)上何暇,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音凛驮,去河邊找鬼裆站。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宏胯。 我是一名探鬼主播羽嫡,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肩袍!你這毒婦竟也來了杭棵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤了牛,失蹤者是張志新(化名)和其女友劉穎颜屠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹰祸,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡甫窟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛙婴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粗井。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖街图,靈堂內(nèi)的尸體忽然破棺而出浇衬,到底是詐尸還是另有隱情,我是刑警寧澤餐济,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布耘擂,位于F島的核電站,受9級特大地震影響絮姆,放射性物質(zhì)發(fā)生泄漏醉冤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一篙悯、第九天 我趴在偏房一處隱蔽的房頂上張望蚁阳。 院中可真熱鬧,春花似錦鸽照、人聲如沸螺捐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽定血。三九已至,卻和暖如春诞外,著一層夾襖步出監(jiān)牢的瞬間糠悼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工浅乔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倔喂,地道東北人铝条。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像席噩,于是被迫代替她去往敵國和親班缰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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