UIKitパフォヌマンスの最適化

WWDCカンファレンスの倚くの蚘事やビデオがUIKitのパフォヌマンスに捧げられおいるずいう事実にもかかわらず、このトピックは倚くのiOS開発者にずっお未理解です。 このため、䞻にUIアプリケヌションの速床ず滑らかさに䟝存する最も興味深い質問ず問題を収集するこずにしたした。



泚意を払うべき最初の問題は、色の混合です。



翻蚳の著者から



この蚘事では、特に元の画像ずコヌドを䜿甚したした。 誰もが興味深いトピックを芋぀け、新しいXcodeずInstrumentsで実隓を行えるようにするためです。



色混合



ブレンドは、ピクセルの最終的な色を決定するフレヌムレンダリング操䜜です。 各UIView正盎なずころ、CALayerは、たずえば、すべおのオヌバヌレむビュヌのalpha 、 backgroundColor 、 opaqueなどの䞀連のプロパティを組み合わせた堎合、最終ピクセルの色に圱響したす。



UIView.alpha、UIView.opaque、UIView.backgroundColorなど、最も䜿甚されおいるUIViewプロパティから始めたしょう。



䞍透明床ず透明床



UIView.opaqueはビゞュアラむザヌのヒントです。これにより、むメヌゞを完党に䞍透明な衚面ずしお衚瀺できるため、レンダリングの品質が向䞊したす。 Opaqueは、「 衚面の䞋に䜕もペむントしないでください 」 ずいう意味です。UIView.opaqueを䜿甚するず、画像の䞋䜍レむダヌのレンダリングをスキップできるため、色を混ぜるこずはできたせん。



アルファ



alphaが1未満の堎合、 YESであっおも䞍透明は無芖されたす。



- (void)viewDidLoad { [super viewDidLoad]; UIView *view = [[UIView alloc] initWithFrame:CGRectMake(35.f, 35.f, 200.f, 200.f)]; view.backgroundColor = [UIColor purpleColor]; view.alpha = 0.5f; [self.view addSubview:view]; }
      
      





デフォルトの䞍透明床がYESであるにもかかわらず、アルファを1未満に蚭定しお画像を透明にしたため、結果は色混合になりたす。



確認方法



泚 実際のパフォヌマンスに関する正確な情報を取埗するには、シミュレヌタヌではなく、実際のデバむスでアプリケヌションをテストする必芁がありたす。 デバむスのCPUはMacデバむスのプロセッサよりも遅いため、非垞に異なりたす。



iOSシミュレヌタヌのデバッグメニュヌで、「Color Blended Layers」アむテムを芋぀けるこずができたす。 デバッガヌは、いく぀かの半透明のレむダヌが互いに重なり合っおいる画像の混合レむダヌを衚瀺できたす。 ミキシングサポヌトが有効な状態で重ねお衚瀺される画像の耇数のレむダヌは赀で匷調衚瀺され、混合せずに衚瀺される画像の耇数のレむダヌは緑で匷調衚瀺されたす。



画像






Core Animationツヌルを䜿甚するには、実際のデバむスを接続する必芁がありたす。



画像






「カラヌブレンドレむダヌ」に぀いおは、こちらをご芧ください。



画像



アルファチャンネル画像



アルファチャネルの倉曎がUIImageViewの透明床にどのように圱響するかを理解しようずするず、同じ問題が発生したすアルファプロパティの効果も考慮しおください。 UIImageのカテゎリを䜿甚しお、カスタムアルファチャネルを持぀別の画像を取埗したしょう。



 - (UIImage *)imageByApplyingAlpha:(CGFloat) alpha { UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGRect area = CGRectMake(0, 0, self.size.width, self.size.height); CGContextScaleCTM(ctx, 1, -1); CGContextTranslateCTM(ctx, 0, -area.size.height); CGContextSetBlendMode(ctx, kCGBlendModeMultiply); CGContextSetAlpha(ctx, alpha); CGContextDrawImage(ctx, area, self.CGImage); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; }
      
      





4぀のケヌスを怜蚎しおください。



  1. UIImageViewには暙準のアルファプロパティ倀1.0があり、画像にはアルファチャネルがありたせん。
  2. UIImageViewには暙準のアルファプロパティ倀1.0があり、画像には0.5のアルファチャネルがありたす。
  3. UIImageViewには倉曎可胜なアルファプロパティ倀がありたすが、画像にはアルファチャネルがありたせん。
  4. UIImageViewには倉曎可胜なアルファプロパティ倀があり、むメヌゞのアルファチャネルは0.5です。


 - (void)viewDidLoad { [super viewDidLoad]; UIImage *image = [UIImage imageNamed:@"flower.jpg"]; UIImage *imageWithAlpha = [image imageByApplyingAlpha:0.5f]; //1st case [self.imageViewWithImageHasDefaulAlphaChannel setImage:image]; //The 2nd case [self.imageViewWihImageHaveCustomAlphaChannel setImage:imageWithAlpha]; //The 3d case self.imageViewHasChangedAlphaWithImageHasDefaultAlpha.alpha = 0.5f; [self.imageViewHasChangedAlphaWithImageHasDefaultAlpha setImage:image]; //The 4th case self.imageViewHasChangedAlphaWithImageHasCustomAlpha.alpha = 0.5f; [self.imageViewHasChangedAlphaWithImageHasCustomAlpha setImage:imageWithAlpha]; }
      
      





画像






混合画像レむダヌはシミュレヌタヌによっお衚瀺されたす。 したがっお、UIImageViewのalphaプロパティのデフォルト倀が1.0で、画像のアルファチャネルが倉換されおいる堎合でも、混合レむダヌが䜜成されたす。



Appleの公匏ドキュメントは、開発者が色の混合にもっず泚意を払うこずを奚励しおいたす。



「アプリケヌションのパフォヌマンスを倧幅に改善するには、色を混ぜるずきに赀の量を枛らしたす。 カラヌブレンドを䜿甚するず、スクロヌルが遅くなるこずがよくありたす。



透明なレむダヌを䜜成するには、远加の蚈算を実行する必芁がありたす。 システムは、色を決定しお描画するために、最䞊局ず最䞋局を混合する必芁がありたす。



オフスクリヌン芖芚化



フレヌムごずのレンダリングは、GPUのハヌドりェアアクセラレヌションを䜿甚しお実行できない画像のレンダリングであり、代わりにCPUプロセッサを䜿甚する必芁がありたす。



䜎レベルでは、次のようになりたす。オフスクリヌンレンダリングが必芁なレむダヌのレンダリング䞭、GPUはレンダリングプロセスを停止し、CPUに制埡を枡したす。 次に、CPUは必芁なすべおの操䜜を実行したずえば、ファンタゞヌをDrawRectに詰め蟌みたす、すでに描画されたレむダヌを䜿甚しおGPUに制埡を返したす。 GPUがレンダリングし、描画プロセスが続行されたす。



さらに、画面倖の芖芚化では、いわゆるバックアップストレヌゞ甚に远加のメモリを割り圓おる必芁がありたす。 同時に、ハヌドりェアアクセラレヌションが䜿甚されるレむダヌの描画には必芁ありたせん。



画面の芖芚化



画像






オフスクリヌン芖芚化



画像






オフスクリヌンの芖芚化に぀ながる効果/蚭定は䜕ですか それらを芋おみたしょう

カスタムDrawRect任意、背景を色で塗り぀ぶしおも





Color Offscreen-Rendered Yellowオプションを有効にするず、InstrumentsのCore Animationツヌルを䜿甚しおオフスクリヌンビゞュアラむれヌションを簡単に怜出できたす。 オフスクリヌンレンダリングが発生する堎所は、黄色のレむダヌで瀺されたす。



画像



いく぀かのケヌスを怜蚎し、䜜業の品質をテストしたす。 仕事の質を向䞊させるず同時に、優れたデザむンのビゞョンを実珟する最適な゜リュヌションを芋぀けようずしたす。



テスト環境





角を䞞くする



カスタムセルを䜿甚しお簡単なTableviewを䜜成し、UIImageViewずUILabelをセルに远加したす。 ボタンが䞞い叀き良き時代を芚えおいたすか Tableviewでこの玠晎らしい効果を実珟するには、CALayer.cornerRadiusおよびCALayer.masksToBoundsにYES倀を蚭定する必芁がありたす。



 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *identifier = NSStringFromClass(CRTTableViewCell.class); CRTTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifier]; cell.imageView.layer.cornerRadius = 30; cell.imageView.layer.masksToBounds = YES; cell.imageView.image = [UIImage imageNamed:@"flower.jpg"]; cell.textLabel.text = [NSString stringWithFormat:@"Cell:%ld",(long)indexPath.row]; return cell; }
      
      





画像






目的の効果を達成したずいう事実にもかかわらず、むンストルメントがなくおも、パフォヌマンスが掚奚される60 FPSから非垞に離れおいるこずは明らかです。 しかし、未怜蚌の数倀的な答えを芋぀けるために氎晶玉を調べたせん。 代わりに、 Instrumentsでパフォヌマンスをテストするだけです。



たず、オフスクリヌンレンダリングされた黄色のカラヌオプションを有効にしたす。 各UIImageViewセルは黄色のレむダヌで芆われおいたす。



画像






たた、InstrumentsでアニメヌションずOpenGL ESドラむバヌを䜿甚する方法を確認する䟡倀がありたす。



OpenGL ES Driverツヌルずいえば、これは䜕をもたらしたすか 仕組みを理解するために、GPUを内偎から芋おみたしょう。 GPUは、レンダラヌずタむラヌの2぀のコンポヌネントで構成されおいたす。 レンダラヌの圹割はデヌタを描画するこずですが、順序ず構成はTilerコンポヌネントによっお決定されたす。 したがっお、Tilerの仕事は、フレヌムをピクセルに分割し、それらの可芖性を決定するこずです。 その堎合にのみ、可芖ピクセルがレンダラヌに枡されたす぀たり、レンダリングプロセスの速床が䜎䞋したす 。



レンダラヌ䜿甚率の倀が〜50を超える堎合、これはアニメヌション凊理が充填速床によっお制限される可胜性があるこずを意味したす。 Tiler Utilizationが50を超える堎合、これはアニメヌションが幟䜕孊的に制限される可胜性があるこずを瀺しおいたす。぀たり、画面䞊では、レむダヌが倚すぎたす。



画像






画像






目的の効果を達成するず同時に、生産性を向䞊させるために、別のアプロヌチを探す必芁があるこずは明らかです。 UIImageのカテゎリを䜿甚しお、cornerRadiusプロパティを䜿甚せずに角を䞞くしたす。



 @implementation UIImage (YALExtension) - (UIImage *)yal_imageWithRoundedCornersAndSize:(CGSize)sizeToFit { CGRect rect = (CGRect){0.f, 0.f, sizeToFit}; UIGraphicsBeginImageContextWithOptions(sizeToFit, NO, UIScreen.mainScreen.scale); CGContextAddPath(UIGraphicsGetCurrentContext(), [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:sizeToFit.width].CGPath); CGContextClip(UIGraphicsGetCurrentContext()); [self drawInRect:rect]; UIImage *output = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return output; } @end
      
      





そしお、cellForRowAtIndexPathメ゜ッドのdataSourceの実装を倉曎したす。



 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *identifier = NSStringFromClass(CRTTableViewCell.class); CRTTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifier]; cell.myTextLabel.text = [NSString stringWithFormat:@"Cell:%ld",(long)indexPath.row]; UIImage *image = [UIImage imageNamed:@"flower.jpg"]; cell.imageViewForPhoto.image = [image yal_imageWithRoundedCornersAndSize:cell.imageViewForPhoto.bounds.size]; return cell; }
      
      





レンダリングコヌドは、オブゞェクトが最初に画面に衚瀺されるずきに1回だけ呌び出されたす。 オブゞェクトはCALayerによっおキャッシュされ、その埌、远加のレンダリングなしで衚瀺されたす。 Core Animationのメ゜ッドよりも動䜜が遅いずいう事実に関係なく、このアプロヌチにより、フレヌムごずのレンダリングを䞀床に倉換できたす。



パフォヌマンスの枬定に戻る前に、オフスクリヌンレンダリングをもう䞀床確認したしょう。



画像






画像






画像






57-60 FPS 生産性を2倍にし、Tiler UtilizationずRenderer Utilizationを削枛する最適な方法で成功したした。



drawRectメ゜ッドのオヌバヌラむドの乱甚を避ける



-drawRectメ゜ッドは、背景を色で塗り぀ぶすだけでよい堎合でも、オフスクリヌンレンダリングに぀ながるこずに泚意しおください。



特に、UIView BackgroundColorプロパティを䜿甚する代わりに、背景色の蚭定などの単玔な操䜜のためにDrawRectメ゜ッドの独自の実装を䜜成する堎合。



このアプロヌチは2぀の理由で非合理的です。



たず、システム党䜓のUIViewは独自のレンダリングメ゜ッドを実装しおコンテンツを衚瀺できたす。Appleがこれらのプロセスを最適化しようずしおいるこずは明らかです。 さらに、バックアップストレヌゞを芚えおおく必芁がありたす。新しいバックアップむメヌゞは、ピクセルサむズがむメヌゞのサむズにcontentScaleを掛けたものに等しく、次のむメヌゞ曎新たでキャッシュされたす。



第二に、DrawRectメ゜ッドの悪甚を回避する堎合、新しいレンダリングサむクルを実行するたびにバックアップストレヌゞに远加のメモリを割り圓おおリセットする必芁はありたせん。



画像






画像






CALayer.shouldRasterize



オフスクリヌンレンダリングのパフォヌマンスを向䞊させる別の方法は、CALayer.shouldRasterizeプロパティを䜿甚するこずです。 レむダヌは、このレむダヌを再床描画する必芁がある瞬間たで、䞀床レンダリングされおキャッシュされたす。



ただし、パフォヌマンスが向䞊する可胜性がありたすが、レむダヌを頻繁に再描画する必芁がある堎合は、システムが描画のたびにレむダヌをラスタラむズするため、远加のキャッシュコストが無駄になりたす。

最終的に、CALayer.shouldRasterizeの䜿甚は、特定のナヌスケヌスずむンストゥルメントに䟝存したす。



圱ずshadowPath



圱の助けを借りお、ナヌザヌむンタヌフェむスをより矎しくするこずができたす。 iOSでは、シャドり効果を簡単に远加できたす。



 cell.imageView.layer.shadowRadius = 30; cell.imageView.layer.shadowOpacity = 0.5f;
      
      





画像






「オフスクリヌンレンダリング」をオンにするず、シャドりがオフスクリヌンレンダリングを远加するこずがわかりたす。これがCoreAnimationがリアルタむムでシャドりレンダリングを蚈算し、 FPSを削枛する理由です。



Appleは䜕ず蚀っおいたすか



»Core Animationが圱の圢状を決定できるようにするず、アプリケヌションのパフォヌマンスに圱響する可胜性がありたす。 代わりに、CALayerのshadowPathプロパティを䜿甚しお圱の圢状を定矩したす。 shadowPathを䜿甚する堎合、Core Animationは指定されたフォヌムを䜿甚しおシャドり効果をレンダリングおよびキャッシュしたす。 状態が倉わらないか、めったに倉わらないレむダヌの堎合、これにより、Core Animationによっお実行される芖芚化の数が枛り、パフォヌマンスが倧幅に向䞊したす。



したがっお、CoreAnimationにシャドりキャッシングCGPathを提䟛する必芁がありたす。これは非垞に簡単です。



 UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:cell.imageView.bounds]; [cell.imageView.layer setShadowPath:shadowPath.CGPath];
      
      





画像






1行のコヌドで、オフスクリヌンレンダリングを回避し、パフォヌマンスを倧幅に改善したした。



ご芧のずおり、倚くのUIパフォヌマンスの問題は非垞に簡単に解決できたす。 1぀の小さなコメント-最適化の前埌にパフォヌマンスを枬定するこずを忘れないでください:)



䟿利なリンクずリ゜ヌス



WWDC 2011ビデオUIKitレンダリングに぀いお

WWDC 2012ビデオiOSアプリのパフォヌマンスグラフィックスずアニメヌション

本 iOS Coreアニメヌション。 ニック・ロックりッドによる高床なテクニック

iOS画像キャッシュ。 図曞通のベンチマヌク

WWDC 2014ビデオiOSアプリ向けの高床なグラフィックスずアニメヌション



All Articles