PhotoKit相簿的效能優化
有關PhotoKit的基礎知識,參考我的另一篇博文: 優雅的建立一個相簿管理類。
這篇文章記錄一下在實際專案中,自定義相簿的優化工作。
之前的文章提到過,獲取照片高清原圖使用下面的方法:
PHImageManager *manger = [PHImageManager defaultManager];
PHImageRequestOptions * options = [[PHImageRequestOptions alloc] init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
options.synchronous = YES;
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.networkAccessAllowed = NO;
[manger requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
//獲取照片 result
}];
在實際的使用過程中,如果涉及多張照片迴圈獲取原圖,就會出現記憶體大幅度上升的問題。通過Allcation就行記憶體檢測的時候,發現正是該方法會佔用很大的記憶體。
經過查詢資料和自己的驗證後,發現可以通過下面的方法獲取圖片。這樣記憶體會穩定,就不會引起這樣記憶體的問題。
[manger requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
UIImage *image = [UIImage imageWithData:imageData];
//獲取照片 image
}];
該方法是獲取先圖片的二進位制流,然後轉化為UImage。
另外,對於滑動相簿的時候,記憶體也會出現一定的增大,雖然不會造成明顯的卡頓現象。
但官方也給出了PhotoKit的快取機制介面,更好的優化記憶體,提升滑動的流暢性。
具體方法如下:
在當前擁有UICollectionView的檢視控制器中:
@property (nonatomic, assign) CGRect previousPreheatRect;
@property (nonatomic, strong) PHCachingImageManager *imageManager;
- (PHCachingImageManager *)imageManager
{
if (_imageManager == nil) {
_imageManager = [PHCachingImageManager new];
}
return _imageManager;
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self updateCachedAssets];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self updateCachedAssets];
}
該快取方案的原理就是快取frame範圍內所對應的顯示到cell上的照片的PHAsset物件。這樣在滑動的時候直接讀取快取裡面的資料,避免了反覆根據index去給cell賦值的操作。
- (void)updateCachedAssets{
BOOL isViewVisible = [self isViewLoaded] && self.view.window != nil;
if (!isViewVisible) { return; }
// The preheat window is twice the height of the visible rect
CGRect preheatRect = self.collectionView.bounds;
preheatRect = CGRectInset(preheatRect, 0.0, -0.5 * CGRectGetHeight(preheatRect));
// If scrolled by a "reasonable" amount...
CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0) {
// Compute the assets to start caching and to stop caching
NSMutableArray *addedIndexPaths = [NSMutableArray array];
NSMutableArray *removedIndexPaths = [NSMutableArray array];
[self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect addedHandler:^(CGRect addedRect) {
NSArray *indexPaths = [self apple_indexPathsForElementsInRect:addedRect];
[addedIndexPaths addObjectsFromArray:indexPaths];
} removedHandler:^(CGRect removedRect) {
NSArray *indexPaths = [self apple_indexPathsForElementsInRect:removedRect];
[removedIndexPaths addObjectsFromArray:indexPaths];
}];
NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];
CGSize itemSize = CGSizeMake((ScreenWidth-15)/3, (ScreenWidth-15)/3);
CGSize targetSize = CGSizeScale(itemSize, self.traitCollection.displayScale);
[self.imageManager startCachingImagesForAssets:assetsToStartCaching
targetSize:targetSize
contentMode:PHImageContentModeAspectFill
options:nil];
[self.imageManager stopCachingImagesForAssets:assetsToStopCaching
targetSize:targetSize
contentMode:PHImageContentModeAspectFill
options:nil];
self.previousPreheatRect = preheatRect;
}
}
- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect addedHandler:(void (^)(CGRect addedRect))addedHandler removedHandler:(void (^)(CGRect removedRect))removedHandler
{
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);
}
}
- (NSArray *)apple_indexPathsForElementsInRect:(CGRect)rect
{
NSArray *allLayoutAttributes = [self.collectionView.collectionViewLayout layoutAttributesForElementsInRect:rect];
if (allLayoutAttributes.count == 0) { return nil; }
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];
for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {
NSIndexPath *indexPath = layoutAttributes.indexPath;
[indexPaths addObject:indexPath];
}
return indexPaths;
}
- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths
{
if (indexPaths.count == 0) { return nil; }
NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
for (NSIndexPath *indexPath in indexPaths) {
if (indexPath.item < self.fetchResult.count && indexPath.item != 0) {
PHAsset *asset = self.fetchResult[self.fetchResult.count-indexPath.item];
[assets addObject:asset];
}
}
return assets;
}
END.
相關文章
- 【前端效能優化】vue效能優化前端優化Vue
- Android效能優化——效能優化的難題總結Android優化
- 效能優化漫談之七:效能優化的誤區優化
- Flutter的效能優化Flutter優化
- CCSpriteBatchNode的優化效能BAT優化
- 效能優化優化
- 效能優化案例-SQL優化優化SQL
- 【效能優化】ORACLE資料庫效能優化概述優化Oracle資料庫
- iOS PhotoKit 初用iOS
- 前端效能優化(JS/CSS優化,SEO優化)前端優化JSCSS
- 前端效能優化的點前端優化
- iOS 效能優化的探索iOS優化
- 急性者的效能優化優化
- Android效能優化----卡頓優化Android優化
- 前端效能優化 --- 圖片優化前端優化
- [效能優化]DateFormatter深度優化探索優化ORM
- MySQL 效能優化之索引優化MySql優化索引
- Web效能優化:圖片優化Web優化
- MySQL 效能優化之SQL優化MySql優化
- Android效能優化篇之計算效能優化Android優化
- mysql效能優化MySql優化
- Redis 效能優化Redis優化
- 效能優化有感優化
- react效能優化React優化
- javascript效能優化JavaScript優化
- Javascript 效能優化JavaScript優化
- php效能優化PHP優化
- 前端效能優化前端優化
- JVM效能優化JVM優化
- java效能優化Java優化
- TableView效能優化View優化
- mongodb效能優化MongoDB優化
- Canvas效能優化Canvas優化
- web效能優化Web優化
- MySQL——效能優化MySql優化
- oracle 效能優化Oracle優化
- React 效能優化React優化
- Spark效能優化Spark優化