├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md └── UI 渲染性能优化 ├── .DS_Store ├── PixelsOnScreen ├── .DS_Store ├── PixelsOnScreen.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── PixelsOnScreen │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── Images │ │ ├── 001.imageset │ │ │ ├── 001.jpeg │ │ │ └── Contents.json │ │ ├── 002.imageset │ │ │ ├── 002.jpeg │ │ │ └── Contents.json │ │ ├── 003.imageset │ │ │ ├── 003.jpeg │ │ │ └── Contents.json │ │ ├── 004.imageset │ │ │ ├── 004.jpeg │ │ │ └── Contents.json │ │ ├── 005.imageset │ │ │ ├── 005.jpeg │ │ │ └── Contents.json │ │ ├── 006.imageset │ │ │ ├── 006.jpeg │ │ │ └── Contents.json │ │ ├── 007.imageset │ │ │ ├── 007.jpeg │ │ │ └── Contents.json │ │ ├── 008.imageset │ │ │ ├── 008.jpeg │ │ │ └── Contents.json │ │ └── Contents.json │ ├── applause.imageset │ │ ├── Contents.json │ │ ├── applause@2x.png │ │ └── applause@3x.png │ └── house.imageset │ │ ├── Contents.json │ │ └── house.jpeg │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ListViewController.h │ ├── ListViewController.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── 屏幕图像显示原理和性能优化.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | UI 渲染性能优化/PixelsOnScreen/.DS_Store 65 | UI 渲染性能优化/PixelsOnScreen/.DS_Store 66 | UI 渲染性能优化/PixelsOnScreen/.DS_Store 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ShannonChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOSAppOptimization 2 | iOS App 性能优化理论与实践 3 | 4 | 5 | 6 | ### 1. 基础 7 | #### 1.1 Instruments 的使用 8 | - [Improving Your App with Instruments](https://developer.apple.com/videos/play/wwdc2014/418/) 9 | - [What every iOS Developer should be doing with Instruments](https://medium.com/@kazmiekr/what-every-ios-developer-should-be-doing-with-instruments-d1661eeaf64f) 10 | - [iOS 性能优化:Instruments 工具的救命三招](https://blog.leancloud.cn/2835/) 11 | - [Instruments Tutorial with Swift: Getting Started](https://www.raywenderlich.com/166125/instruments-tutorial-swift-getting-started) 12 | - [使用 Instruments 做 iOS 程序性能调试](http://www.samirchen.com/use-instruments/) 13 | 14 | #### 1.2 日志系统 15 | - [CocoaLumberjack/CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack) 16 | - Bugly 17 | 18 | ### 2. 性能监控 19 | #### 2.1 App 整体监控 20 | - [移动端性能监控方案Hertz](http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745918&idx=2&sn=911bd1a1d863b5be4b501b5099f00d55&chksm=bd12b7338a653e25c736d9706910bd336a3a86823f264fd4df08b3eb5fdd2530a98ab3cc1ba7&mpshare=1&scene=23&srcid=0427otTfU3sihcE91joRnEGv#rd) 21 | - [微信读书 iOS 质量保证及性能监控](http://wereadteam.github.io/2016/12/12/Monitor/) 22 | - [微信客户端性能监控和优化简述](http://www.infoq.com/cn/news/2017/07/wechat-client-performance-tuning) 23 | - [ 《iOS监控编程》(作者:陈奕龙)](https://xiaozhuanlan.com/godeye) 24 | - [从 iOS 角度出发,剖析移动端性能监控的技术原理 - 趣直播](https://link.jianshu.com/?t=http%3A%2F%2Fm.quzhiboapp.com%2F%3F%23%21%2Fintro%2F392) 25 | - [移动端监控体系之技术原理剖析](https://www.jianshu.com/p/8123fc17fe0e) 26 | - [ iOS 性能监控方案 - 沪江技术学院](https://github.com/aozhimin/iOS-Monitor-Platform) 27 | - [aozhimin/iOS-Monitor-Platform](https://github.com/aozhimin/iOS-Monitor-Platform):iOS 性能监控 SDK —— Wedjat(华狄特)开发过程的调研和整理 28 | - [didi/DoraemonKit](https://github.com/didi/DoraemonKit#%E4%B8%89%E6%80%A7%E8%83%BD%E6%A3%80%E6%B5%8B) 29 | 30 | #### 2.2 卡顿检测和监控 31 | - [微信iOS卡顿监控系统](http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207890859&idx=1&sn=e98dd604cdb854e7a5808d2072c29162&mpshare=1&scene=23&srcid=0705h7FPQcWYxo0OMO63B5Aj#rd) 32 | - [iOS应用UI线程卡顿监控 - MrPeak](https://mp.weixin.qq.com/s?__biz=MzI5MjEzNzA1MA==&mid=2650264136&idx=1&sn=052c1db8131d4bed8458b98e1ec0d5b0&chksm=f406837dc3710a6b49e76ce3639f671373b553e8a91b544e82bb8747e9adc7985fea1093a394#rd) 33 | - [如何检测 iOS app 卡顿导致的系统强杀 - MrPeak](https://mp.weixin.qq.com/s/FskmoclDyo9ho1bTU28XpA) 34 | - [Instrument调试界面卡顿](http://www.jianshu.com/p/9dbbc91c8059) 35 | - [iOS 稳定性问题治理:卡死崩溃监控原理及最佳实践 - 字节跳动技术团队](https://mp.weixin.qq.com/s/cEfIZGtUojKKbhIfUyhTMw) 36 | 37 | ### 3. 性能优化 38 | #### 3.1 App 整体优化 39 | - [skyming/iOS-Performance-Optimization](https://github.com/skyming/iOS-Performance-Optimization) 40 | - [微信读书 iOS 性能优化总结](http://wereadteam.github.io/2016/05/03/WeRead-Performance/) 41 | - [Performance Overview](https://developer.apple.com/library/content/documentation/Performance/Conceptual/PerformanceOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40001410) 42 | - [关于 iOS 性能和稳定性不容错过的资源集锦](https://xiaozhuanlan.com/topic/1907362845) 43 | 44 | #### 3.2 UI 和图片加载相关的优化 45 | - [优化UITableViewCell高度计算的那些事](http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/) 46 | - [Perfect Smooth Scrolling in UITableViews](https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5)([中文翻译](https://southpeak.github.io/2015/12/20/perfect-smooth-scrolling-in-uitableviews/)) 47 | - [iOS 保持界面流畅的技巧](http://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/) 48 | - [UIKit性能调优实战讲解](https://github.com/bestswifter/blog/blob/master/articles/uikit-optimization.md) 49 | - [iOS 高效添加圆角效果实战讲解](https://bestswifter.com/efficient-rounded-corner/) 50 | - [UITableView优化技巧](http://www.cocoachina.com/ios/20150602/11968.html) 51 | - [iOS图片加载速度极限优化—FastImageCache解析](https://blog.cnbang.net/tech/2578/) 52 | 53 | #### 3.3 耗电量检测和优化 54 | - [iOS耗电量测试方法及其数据收集](https://mp.weixin.qq.com/s?__biz=MjM5ODY4ODIxOA==&mid=2653201881&idx=1&sn=d4c9e65ea8af5ec1d8835bc32351b10f&chksm=bd16e16c8a61687afd973568e003e2aa6c20e3a9ecd9b93b11dc67586c13ebaa3b308eed3095&mpshare=1&scene=1&srcid=0802WyHYGUMINTB5fIYeBM8w#rd) 55 | 56 | #### 3.4 网络优化 57 | - [深度优化iOS网络模块 - MrPeak](https://zhuanlan.zhihu.com/p/22943142) 58 | - [移动 APP 网络优化概述 - bang](https://blog.cnbang.net/tech/3531/) 59 | 60 | #### 3.5 Hybrid 优化 61 | - [移动 H5 首屏秒开优化方案探讨 - bang](https://blog.cnbang.net/tech/3477/) 62 | 63 | 64 | #### 3.6. 启动速度优化 65 | - [iOS App冷启动治理:来自美团外卖的实践](https://juejin.im/post/5c0a17d6e51d4570cf60d102) 66 | - [阿里数据iOS端启动速度优化的一些经验](http://www.cocoachina.com/ios/20180202/22120.html) 67 | - [iOS App 启动性能优化 - bugly](http://www.10tiao.com/html/330/201708/2653579242/1.html) 68 | - [优化 App 的启动时间](http://yulingtianxia.com/blog/2016/10/30/Optimizing-App-Startup-Time/) 69 | - [今日头条iOS客户端启动速度优化](https://mp.weixin.qq.com/s/oiX4W2TgOn1otvzVVqdPWg) 70 | - [如何精确度量 iOS App 的启动时间](https://www.jianshu.com/p/c14987eee107) 71 | - [App Startup Time: Past, Present, and Future - WWDC2017](https://developer.apple.com/videos/play/wwdc2017/413) 72 | - [抖音品质建设 - iOS启动优化《原理篇》](https://mp.weixin.qq.com/s/3-Sbqe9gxdV6eI1f435BDg) 73 | - [抖音品质建设 - iOS启动优化《实战篇》](https://mp.weixin.qq.com/s/ekXfFu4-rmZpHwzFuKiLXw) 74 | - [抖音研发实践:基于二进制文件重排的解决方案 APP启动速度提升超15%](https://mp.weixin.qq.com/s/Drmmx5JtjG3UtTFksL6Q8Q) 75 | - [Optimizing App Launch - WWDC19](https://developer.apple.com/videos/play/wwdc2019/423/) 76 | - [iOS应用启动性能优化资料](https://everettjf.github.io/2018/08/06/ios-launch-performance-collection/) 77 | - [干货 | Trip.com APP 启动优化实践 - 携程技术](https://mp.weixin.qq.com/s/smWjs2X8HWvcvKW_DSXYJA) 78 | 79 | #### 3.7 安装包瘦身(App size 优化) 80 | - [iPhone安装包的优化](https://techblog.toutiao.com/2016/12/27/iphone/) 81 | - [iOS App 瘦身实践总结](https://juejin.im/post/5800ef71a0bb9f0058736caa) 82 | - [iOS微信安装包瘦身](https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207986417&idx=1&sn=77ea7d8e4f8ab7b59111e78c86ccfe66&3rd=MzA3MDU4NTYzMw==&scene=6#rd) 83 | - [iOS App安装包瘦身](http://willwei.me/2017/04/19/iOS%20App%E5%AE%89%E8%A3%85%E5%8C%85%E7%98%A6%E8%BA%AB/)(文章最后的参考资料不错) 84 | - [pa文件“减肥”初探](https://www.jianshu.com/p/a72d03e92c80) 85 | - [Reducing the size of my App - Apple Technical Q&A](https://developer.apple.com/library/archive/qa/qa1795/_index.html) 86 | - [iOS 瘦包,常见方式梳理](https://xiaozhuanlan.com/topic/7801394625) 87 | - [正经分析iOS包大小优化 - 搜狐技术产品](https://mp.weixin.qq.com/s/TI1PHPAuCQwfvZk47L89lg) 88 | 89 | 90 | ### 4. 内存问题 91 | #### 4.1 内存泄漏检测 92 | - [facebook/FBMemoryProfiler](https://github.com/facebook/FBMemoryProfiler) 93 | - [MLeaksFinder:精准 iOS 内存泄露检测工具](http://wereadteam.github.io/2016/02/22/MLeaksFinder/) 94 | - [MLeaksFinder 新特性](http://wereadteam.github.io/2016/07/20/MLeaksFinder2/) 95 | - [Tencent/OOMDetector](https://github.com/Tencent/OOMDetector?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io):一个iOS内存监控组件,应用此组件可以帮助你轻松实现OOM监控、大内存分配监控、内存泄漏检测等功能。 96 | - [iOS内存泄漏自动检测工具PLeakSniffer](https://mp.weixin.qq.com/s/qo8nu71iw_a1bhMCFIoA4Q) 97 | - Memory Graph 98 | - [Xcode8调试黑科技:Memory Graph实战解决闭包引用循环问题](https://www.jianshu.com/p/f792f9aa2e45) 99 | - [iOS — Identifying Memory Leaks using the Xcode Memory Graph Debugger](https://medium.com/zendesk-engineering/ios-identifying-memory-leaks-using-the-xcode-memory-graph-debugger-e84f097b9d15) 100 | - [Automatic memory leak detection on iOS](https://code.facebook.com/posts/583946315094347/automatic-memory-leak-detection-on-ios/) 101 | 102 | 103 | #### 4.2 OOM 问题 104 | - [iOS微信内存监控 - 腾讯WeTest](https://mp.weixin.qq.com/s/r0Q7um7P1p2gIb0aHldyNw) 105 | - [内存占用过高怎么办?iOS图片内存优化指南 - 腾讯 - 张恒铭](https://mp.weixin.qq.com/s/4_UOxUM7d2StQxzb5Sf2rw) 106 | - [iOS性能优化实践:头条抖音如何实现OOM崩溃率下降50%+](https://mp.weixin.qq.com/s/4-4M9E8NziAgshlwB7Sc6g) 107 | - [iOS Out-Of-Memory 原理阐述及方案调研](https://juejin.cn/post/6844903749836603400) 108 | 109 | #### 5. 崩溃日志收集和分析 110 | - [iOS App 连续闪退时如何上报 crash 日志 - MrPeak](https://mp.weixin.qq.com/s/ADj-BT7itSfHVIvyAoseRA) ⭐️ 111 | - [漫谈 iOS Crash 收集框架 - 念茜](https://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=208483273&idx=1&sn=37ee88e06e7426f59f3074c536370317&scene=21)⭐️ 112 | - [Diagnosing Issues Using Crash Reports and Device Logs - Apple Developer](https://developer.apple.com/documentation/xcode/diagnosing-issues-using-crash-reports-and-device-logs) ⭐️ 113 | - [iOS 启动连续闪退保护方案 - 微信读书](https://wereadteam.github.io/2016/05/23/GYBootingProtection/) 114 | - [iOS runtime实用篇--和常见崩溃say good-bye!](https://www.jianshu.com/p/5d625f86bd02) 115 | - [iOS异常捕获](http://www.iosxxx.com/blog/2015-08-29-iosyi-chang-bu-huo.html) 116 | - [大白健康系统--iOS APP运行时Crash自动修复系统](https://neyoufan.github.io/2017/01/13/ios/BayMax_HTSafetyGuard/) 117 | - [运行时防 crash 工具 XXShield](https://github.com/ValiantCat/XXShield) 118 | - [iOS crash 日志堆栈解析](https://juejin.im/post/5adf15f2518825671775f3e1) 119 | - [再谈 iOS App Crash 防护](https://xiaozhuanlan.com/topic/6280793154) 120 | - [iOS Crash分析必备:符号化系统库方法](https://zuikyo.github.io/2016/12/18/iOS%20Crash%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90%E5%BF%85%E5%A4%87%EF%BC%9A%E7%AC%A6%E5%8F%B7%E5%8C%96%E7%B3%BB%E7%BB%9F%E5%BA%93%E6%96%B9%E6%B3%95/) 121 | - [iOS崩溃crash大解析](https://www.jianshu.com/p/1b804426d212) 122 | - 崩溃分析 123 | - [Understanding and Analyzing Application Crash Reports - Apple Developer Center](https://developer.apple.com/library/archive/technotes/tn2151/_index.html)([了解和分析iOS Crash Report](https://juejin.im/post/5c5edb37e51d457f926d2290)) 124 | - [深入iOS系统底层之crash解决方法介绍](https://www.jianshu.com/p/cf0945f9c1f8) 125 | - [深入理解iOS Crash Log](https://blog.csdn.net/Hello_Hwc/article/details/80946318)【推荐阅读】 126 | - [Understanding Crashes and Crash Logs - WWDC 2018](https://developer.apple.com/videos/play/wwdc2018/414/) 127 | 128 | 129 | #### 6. Xcode 编译速度 130 | 131 | - [如何提高 Xcode 的编译速度](https://juejin.im/post/5b21449fe51d4506d33d1187)([Building Faster in Xcode - WWDC 2018 - Videos - Apple Developer](https://developer.apple.com/videos/play/wwdc2018/408)) 132 | - [Optimizing XCode Build Times with XCode 10](https://tech.iheart.com/optimizing-xcode-build-times-with-xcode-10-527bfc0ce27f) 133 | -------------------------------------------------------------------------------- /UI 渲染性能优化/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/.DS_Store -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/.DS_Store -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 58878DC8208EDCB40023527D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 58878DC7208EDCB40023527D /* AppDelegate.m */; }; 11 | 58878DCB208EDCB40023527D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58878DCA208EDCB40023527D /* ViewController.m */; }; 12 | 58878DCE208EDCB40023527D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 58878DCC208EDCB40023527D /* Main.storyboard */; }; 13 | 58878DD0208EDCB60023527D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 58878DCF208EDCB60023527D /* Assets.xcassets */; }; 14 | 58878DD3208EDCB60023527D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 58878DD1208EDCB60023527D /* LaunchScreen.storyboard */; }; 15 | 58878DD6208EDCB60023527D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 58878DD5208EDCB60023527D /* main.m */; }; 16 | 58878DDE208F1D060023527D /* ListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58878DDD208F1D060023527D /* ListViewController.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 58878DC3208EDCB40023527D /* PixelsOnScreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PixelsOnScreen.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 58878DC6208EDCB40023527D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 22 | 58878DC7208EDCB40023527D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 23 | 58878DC9208EDCB40023527D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 24 | 58878DCA208EDCB40023527D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 25 | 58878DCD208EDCB40023527D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | 58878DCF208EDCB60023527D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | 58878DD2208EDCB60023527D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | 58878DD4208EDCB60023527D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | 58878DD5208EDCB60023527D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | 58878DDC208F1D060023527D /* ListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ListViewController.h; sourceTree = ""; }; 31 | 58878DDD208F1D060023527D /* ListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ListViewController.m; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 58878DC0208EDCB40023527D /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 58878DBA208EDCB40023527D = { 46 | isa = PBXGroup; 47 | children = ( 48 | 58878DC5208EDCB40023527D /* PixelsOnScreen */, 49 | 58878DC4208EDCB40023527D /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | 58878DC4208EDCB40023527D /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 58878DC3208EDCB40023527D /* PixelsOnScreen.app */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | 58878DC5208EDCB40023527D /* PixelsOnScreen */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 58878DC6208EDCB40023527D /* AppDelegate.h */, 65 | 58878DC7208EDCB40023527D /* AppDelegate.m */, 66 | 58878DC9208EDCB40023527D /* ViewController.h */, 67 | 58878DCA208EDCB40023527D /* ViewController.m */, 68 | 58878DDC208F1D060023527D /* ListViewController.h */, 69 | 58878DDD208F1D060023527D /* ListViewController.m */, 70 | 58878DCC208EDCB40023527D /* Main.storyboard */, 71 | 58878DCF208EDCB60023527D /* Assets.xcassets */, 72 | 58878DD1208EDCB60023527D /* LaunchScreen.storyboard */, 73 | 58878DD4208EDCB60023527D /* Info.plist */, 74 | 58878DD5208EDCB60023527D /* main.m */, 75 | ); 76 | path = PixelsOnScreen; 77 | sourceTree = ""; 78 | }; 79 | /* End PBXGroup section */ 80 | 81 | /* Begin PBXNativeTarget section */ 82 | 58878DC2208EDCB40023527D /* PixelsOnScreen */ = { 83 | isa = PBXNativeTarget; 84 | buildConfigurationList = 58878DD9208EDCB60023527D /* Build configuration list for PBXNativeTarget "PixelsOnScreen" */; 85 | buildPhases = ( 86 | 58878DBF208EDCB40023527D /* Sources */, 87 | 58878DC0208EDCB40023527D /* Frameworks */, 88 | 58878DC1208EDCB40023527D /* Resources */, 89 | ); 90 | buildRules = ( 91 | ); 92 | dependencies = ( 93 | ); 94 | name = PixelsOnScreen; 95 | productName = MisalignedImages; 96 | productReference = 58878DC3208EDCB40023527D /* PixelsOnScreen.app */; 97 | productType = "com.apple.product-type.application"; 98 | }; 99 | /* End PBXNativeTarget section */ 100 | 101 | /* Begin PBXProject section */ 102 | 58878DBB208EDCB40023527D /* Project object */ = { 103 | isa = PBXProject; 104 | attributes = { 105 | LastUpgradeCheck = 0930; 106 | ORGANIZATIONNAME = ShannonChen; 107 | TargetAttributes = { 108 | 58878DC2208EDCB40023527D = { 109 | CreatedOnToolsVersion = 9.3; 110 | }; 111 | }; 112 | }; 113 | buildConfigurationList = 58878DBE208EDCB40023527D /* Build configuration list for PBXProject "PixelsOnScreen" */; 114 | compatibilityVersion = "Xcode 9.3"; 115 | developmentRegion = en; 116 | hasScannedForEncodings = 0; 117 | knownRegions = ( 118 | en, 119 | Base, 120 | ); 121 | mainGroup = 58878DBA208EDCB40023527D; 122 | productRefGroup = 58878DC4208EDCB40023527D /* Products */; 123 | projectDirPath = ""; 124 | projectRoot = ""; 125 | targets = ( 126 | 58878DC2208EDCB40023527D /* PixelsOnScreen */, 127 | ); 128 | }; 129 | /* End PBXProject section */ 130 | 131 | /* Begin PBXResourcesBuildPhase section */ 132 | 58878DC1208EDCB40023527D /* Resources */ = { 133 | isa = PBXResourcesBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 58878DD3208EDCB60023527D /* LaunchScreen.storyboard in Resources */, 137 | 58878DD0208EDCB60023527D /* Assets.xcassets in Resources */, 138 | 58878DCE208EDCB40023527D /* Main.storyboard in Resources */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXResourcesBuildPhase section */ 143 | 144 | /* Begin PBXSourcesBuildPhase section */ 145 | 58878DBF208EDCB40023527D /* Sources */ = { 146 | isa = PBXSourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 58878DCB208EDCB40023527D /* ViewController.m in Sources */, 150 | 58878DD6208EDCB60023527D /* main.m in Sources */, 151 | 58878DDE208F1D060023527D /* ListViewController.m in Sources */, 152 | 58878DC8208EDCB40023527D /* AppDelegate.m in Sources */, 153 | ); 154 | runOnlyForDeploymentPostprocessing = 0; 155 | }; 156 | /* End PBXSourcesBuildPhase section */ 157 | 158 | /* Begin PBXVariantGroup section */ 159 | 58878DCC208EDCB40023527D /* Main.storyboard */ = { 160 | isa = PBXVariantGroup; 161 | children = ( 162 | 58878DCD208EDCB40023527D /* Base */, 163 | ); 164 | name = Main.storyboard; 165 | sourceTree = ""; 166 | }; 167 | 58878DD1208EDCB60023527D /* LaunchScreen.storyboard */ = { 168 | isa = PBXVariantGroup; 169 | children = ( 170 | 58878DD2208EDCB60023527D /* Base */, 171 | ); 172 | name = LaunchScreen.storyboard; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXVariantGroup section */ 176 | 177 | /* Begin XCBuildConfiguration section */ 178 | 58878DD7208EDCB60023527D /* Debug */ = { 179 | isa = XCBuildConfiguration; 180 | buildSettings = { 181 | ALWAYS_SEARCH_USER_PATHS = NO; 182 | CLANG_ANALYZER_NONNULL = YES; 183 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 184 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 185 | CLANG_CXX_LIBRARY = "libc++"; 186 | CLANG_ENABLE_MODULES = YES; 187 | CLANG_ENABLE_OBJC_ARC = YES; 188 | CLANG_ENABLE_OBJC_WEAK = YES; 189 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 190 | CLANG_WARN_BOOL_CONVERSION = YES; 191 | CLANG_WARN_COMMA = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 195 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 196 | CLANG_WARN_EMPTY_BODY = YES; 197 | CLANG_WARN_ENUM_CONVERSION = YES; 198 | CLANG_WARN_INFINITE_RECURSION = YES; 199 | CLANG_WARN_INT_CONVERSION = YES; 200 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 202 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 203 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 204 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 205 | CLANG_WARN_STRICT_PROTOTYPES = YES; 206 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 207 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 208 | CLANG_WARN_UNREACHABLE_CODE = YES; 209 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 210 | CODE_SIGN_IDENTITY = "iPhone Developer"; 211 | COPY_PHASE_STRIP = NO; 212 | DEBUG_INFORMATION_FORMAT = dwarf; 213 | ENABLE_STRICT_OBJC_MSGSEND = YES; 214 | ENABLE_TESTABILITY = YES; 215 | GCC_C_LANGUAGE_STANDARD = gnu11; 216 | GCC_DYNAMIC_NO_PIC = NO; 217 | GCC_NO_COMMON_BLOCKS = YES; 218 | GCC_OPTIMIZATION_LEVEL = 0; 219 | GCC_PREPROCESSOR_DEFINITIONS = ( 220 | "DEBUG=1", 221 | "$(inherited)", 222 | ); 223 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 224 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 225 | GCC_WARN_UNDECLARED_SELECTOR = YES; 226 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 227 | GCC_WARN_UNUSED_FUNCTION = YES; 228 | GCC_WARN_UNUSED_VARIABLE = YES; 229 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 230 | MTL_ENABLE_DEBUG_INFO = YES; 231 | ONLY_ACTIVE_ARCH = YES; 232 | SDKROOT = iphoneos; 233 | }; 234 | name = Debug; 235 | }; 236 | 58878DD8208EDCB60023527D /* Release */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_ENABLE_MODULES = YES; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_ENABLE_OBJC_WEAK = YES; 247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 248 | CLANG_WARN_BOOL_CONVERSION = YES; 249 | CLANG_WARN_COMMA = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | CODE_SIGN_IDENTITY = "iPhone Developer"; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | ENABLE_STRICT_OBJC_MSGSEND = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu11; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 282 | MTL_ENABLE_DEBUG_INFO = NO; 283 | SDKROOT = iphoneos; 284 | VALIDATE_PRODUCT = YES; 285 | }; 286 | name = Release; 287 | }; 288 | 58878DDA208EDCB60023527D /* Debug */ = { 289 | isa = XCBuildConfiguration; 290 | buildSettings = { 291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 292 | CODE_SIGN_STYLE = Automatic; 293 | DEVELOPMENT_TEAM = L32PN8QKLZ; 294 | INFOPLIST_FILE = PixelsOnScreen/Info.plist; 295 | LD_RUNPATH_SEARCH_PATHS = ( 296 | "$(inherited)", 297 | "@executable_path/Frameworks", 298 | ); 299 | PRODUCT_BUNDLE_IDENTIFIER = com.shannon.com.MisalignedImages; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | TARGETED_DEVICE_FAMILY = "1,2"; 302 | }; 303 | name = Debug; 304 | }; 305 | 58878DDB208EDCB60023527D /* Release */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 309 | CODE_SIGN_STYLE = Automatic; 310 | DEVELOPMENT_TEAM = L32PN8QKLZ; 311 | INFOPLIST_FILE = PixelsOnScreen/Info.plist; 312 | LD_RUNPATH_SEARCH_PATHS = ( 313 | "$(inherited)", 314 | "@executable_path/Frameworks", 315 | ); 316 | PRODUCT_BUNDLE_IDENTIFIER = com.shannon.com.MisalignedImages; 317 | PRODUCT_NAME = "$(TARGET_NAME)"; 318 | TARGETED_DEVICE_FAMILY = "1,2"; 319 | }; 320 | name = Release; 321 | }; 322 | /* End XCBuildConfiguration section */ 323 | 324 | /* Begin XCConfigurationList section */ 325 | 58878DBE208EDCB40023527D /* Build configuration list for PBXProject "PixelsOnScreen" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 58878DD7208EDCB60023527D /* Debug */, 329 | 58878DD8208EDCB60023527D /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | 58878DD9208EDCB60023527D /* Build configuration list for PBXNativeTarget "PixelsOnScreen" */ = { 335 | isa = XCConfigurationList; 336 | buildConfigurations = ( 337 | 58878DDA208EDCB60023527D /* Debug */, 338 | 58878DDB208EDCB60023527D /* Release */, 339 | ); 340 | defaultConfigurationIsVisible = 0; 341 | defaultConfigurationName = Release; 342 | }; 343 | /* End XCConfigurationList section */ 344 | }; 345 | rootObject = 58878DBB208EDCB40023527D /* Project object */; 346 | } 347 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/001.imageset/001.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/001.imageset/001.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/001.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "001.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/002.imageset/002.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/002.imageset/002.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/002.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "002.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/003.imageset/003.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/003.imageset/003.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/003.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "003.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/004.imageset/004.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/004.imageset/004.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/004.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "004.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/005.imageset/005.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/005.imageset/005.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/005.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "005.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/006.imageset/006.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/006.imageset/006.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/006.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "006.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/007.imageset/007.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/007.imageset/007.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/007.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "007.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/008.imageset/008.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/008.imageset/008.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/008.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "008.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/Images/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/applause.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "applause@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "applause@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/applause.imageset/applause@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/applause.imageset/applause@2x.png -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/applause.imageset/applause@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/applause.imageset/applause@3x.png -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/house.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "house.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/house.imageset/house.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShannonChenCHN/iOSAppOptimization/59d5cc60ab66eced6683a16d1d69763237af0301/UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Assets.xcassets/house.imageset/house.jpeg -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/ListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewController.h 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ListViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/ListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewController.m 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import "ListViewController.h" 10 | 11 | 12 | static NSString * const kImageNameKey = @"imageName"; 13 | static NSString * const kTitleKey = @"title"; 14 | 15 | @interface ListViewController () 16 | 17 | @property (nonatomic, strong) NSMutableArray *userInfoList; 18 | 19 | @end 20 | 21 | @implementation ListViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | 27 | self.userInfoList = [NSMutableArray array]; 28 | 29 | for (int i = 1; i <= 8; i++) { 30 | [_userInfoList addObject:@{kImageNameKey : [NSString stringWithFormat:@"00%@", @(i)], 31 | kTitleKey : [NSString stringWithFormat:@"图片 00%@", @(i)] 32 | }]; 33 | } 34 | 35 | [_userInfoList addObjectsFromArray:_userInfoList]; 36 | [_userInfoList addObjectsFromArray:_userInfoList]; 37 | [_userInfoList addObjectsFromArray:_userInfoList]; 38 | [_userInfoList addObjectsFromArray:_userInfoList]; 39 | [_userInfoList addObjectsFromArray:_userInfoList]; 40 | [_userInfoList addObjectsFromArray:_userInfoList]; 41 | [_userInfoList addObjectsFromArray:_userInfoList]; 42 | [_userInfoList addObjectsFromArray:_userInfoList]; 43 | } 44 | 45 | #pragma mark - UITableViewDataSource, UITableViewDelegate 46 | 47 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 48 | return 1; 49 | } 50 | 51 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 52 | return _userInfoList.count; 53 | } 54 | 55 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 56 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath]; 57 | 58 | 59 | NSDictionary *userInfo = _userInfoList[indexPath.row]; 60 | cell.imageView.image = [UIImage imageNamed:userInfo[kImageNameKey]]; 61 | cell.textLabel.text = userInfo[kTitleKey]; 62 | if ((indexPath.row & 0x1) == 0) { 63 | cell.textLabel.layer.shouldRasterize = YES; // 将第奇数个 cell 手动设置为离屏渲染 64 | cell.imageView.layer.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.6].CGColor; 65 | cell.imageView.layer.shadowOpacity = 0.6; 66 | cell.imageView.layer.cornerRadius = 6; 67 | cell.imageView.layer.masksToBounds = YES; 68 | } else { 69 | cell.textLabel.layer.shouldRasterize = NO; 70 | cell.imageView.layer.shadowColor = nil; 71 | cell.imageView.layer.shadowOpacity = 0.0; 72 | cell.imageView.layer.cornerRadius = 0; 73 | cell.imageView.layer.masksToBounds = NO; 74 | } 75 | 76 | // cell.layer.drawsAsynchronously = YES; 77 | 78 | return cell; 79 | } 80 | 81 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 82 | return 100; 83 | } 84 | 85 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 86 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | @property (weak, nonatomic) IBOutlet UIButton *button; 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | } 22 | 23 | - (void)viewDidLayoutSubviews { 24 | [super viewDidLayoutSubviews]; 25 | 26 | _button.frame = CGRectMake(100.03, 494.0, 197.0, 76.0); 27 | } 28 | 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /UI 渲染性能优化/PixelsOnScreen/PixelsOnScreen/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MisalignedImages 4 | // 5 | // Created by ShannonChen on 2018/4/24. 6 | // Copyright © 2018年 ShannonChen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UI 渲染性能优化/屏幕图像显示原理和性能优化.md: -------------------------------------------------------------------------------- 1 | # 屏幕图像显示原理 2 | 3 | > 关键词:像素、位图/纹理、GPU、合成、OpenGL 4 | 5 | 6 | ## 一、基本概念 7 | ### 1. 驱动程序 8 | 9 | 驱动程序是添加到操作系统中的一小块代码,其中包含有关硬件设备的信息。有了此信息,计算机就可以与设备进行通信。对于装有显卡的计算机来说,没有显卡驱动,就不能识别GPU硬件,不能调用其计算资源。 10 | 11 | 驱动程序是硬件的一部分,当你安装新硬件时,驱动程序是一项不可或缺的重要元件。凡是安装一个原本不属于你电脑中的硬件设备时,系统就会要求你安装驱动程序,将新的硬件与电脑系统连接起来。**驱动程序扮演沟通的角色,把硬件的功能告诉电脑系统,并且也将系统的指令传达给硬件,让它开始工作。** 12 | 13 | 参考: 14 | - [驱动 - 百度百科](https://baike.baidu.com/item/%E9%A9%B1%E5%8A%A8/2765136) 15 | - [显卡、显卡驱动、cuda 之间的关系是什么?](https://www.zhihu.com/question/59184480) 16 | 17 | ### 2. 显卡 18 | 19 | #### 2.1 什么是显卡 20 | 显卡(Video card,Graphics card)全称显示接口卡,又称显示适配器,是计算机最基本配置、最重要的配件之一。显卡作为电脑主机里的一个重要组成部分,是电脑进行数模信号转换的设备,承担输出显示图形的任务。显卡接在电脑主板上,它将电脑的数字信号转换成模拟信号让显示器显示出来,同时显卡还是有图像处理能力,可协助CPU工作,提高整体的运行速度。 21 | 22 | #### 2.2 显卡的工作原理 23 | 24 | 数据(data)一旦离开CPU,必须通过4个步骤,最后才会到达显示屏: 25 | 26 | 1.从总线(Bus)进入GPU(Graphics Processing Unit,图形处理器):将CPU送来的数据送到北桥(主桥)再送到GPU(图形处理器)里面进行处理。 27 | 2.从 Video Chipset(显卡芯片组)进入 Video RAM(显存):将芯片处理完的数据送到显存。 28 | 3.从显存进入Digital Analog Converter (= RAM DAC,随机读写存储数—模转换器):从显存读取出数据再送到RAM DAC进行数据转换的工作(数字信号转模拟信号)。但是如果是DVI接口类型的显卡,则不需要经过数字信号转模拟信号。而直接输出数字信号。 29 | 4.从DAC进入显示器(Monitor):将转换完的模拟信号送到显示屏。 30 | 31 | 显示效能是系统效能的一部分,其效能的高低由以上四步所决定,它与显卡的效能(Video Performance)不太一样,如要严格区分,显卡的效能应该受中间两步所决定,因为这两步的资料传输都是在显卡的内部。第一步是由CPU 进入到显卡里面,最后一步是由显卡直接送资料到显示屏上。 32 | 33 | 34 | #### 2.3 显卡的构成 35 | 36 | 显卡通常由总线接口、PCB板、显示芯片、显存、RAMDAC、VGA BIOS、VGA功能插针、D-sub插座及其他外围组件构成,现在的显卡大多还具有VGA、DVI显示器接口或者HDMI接口及S-Video端子和Display Port接口。 37 | 38 | 显示芯片:Video chipset,也叫GPU或VPU,图形处理器或视觉处理器,是显卡的主要处理单元 。 39 | 显存:显存全称显示存储器,亦称帧缓存,它是用来存储显示芯片处理过或者即将读取的渲染数据。如同计算机的内存一样,显存是用来存储图形数据的硬件。 40 | 41 | 参考: 42 | - [显卡 - 百度百科](https://baike.baidu.com/item/%E6%98%BE%E5%8D%A1) 43 | - [显卡 - 维基百科](https://zh.wikipedia.org/wiki/%E6%98%BE%E7%A4%BA%E5%8D%A1) 44 | - [显存 - 维基百科](https://zh.wikipedia.org/wiki/%E6%98%BE%E5%AD%98) 45 | 46 | ### 3. GPU 47 | 48 | #### 3.1 什么是 GPU ? 49 | 图形处理器(英语:Graphics Processing Unit,缩写:GPU),又称显示核心、视觉处理器、显示芯片,是一种专门在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上**图像运算**工作的微处理器。 50 | 51 | #### 3.2 GPU 的作用 52 | 显卡的处理器称为图形处理器(GPU),它是显卡的“心脏”,与CPU类似,只不过GPU是**专为执行复杂的数学和几何计算而设计的**,这些计算是图形渲染所必需的。某些最快速的GPU集成的晶体管数甚至超过了普通CPU。 53 | 54 | 如果CPU想画一个二维图形,只需要发个指令给GPU,如“在坐标位置(x, y)处画个长和宽为a×b大小的长方形”,GPU就可以迅速计算出该图形的所有像素,并在显示器上指定位置画出相应的图形,画完后就通知CPU “我画完了”,然后等待CPU发出下一条图形指令。 55 | 56 | 57 | 有了GPU,CPU就从图形处理的任务中解放出来,可以执行其他更多的系统任务,这样可以大大提高计算机的整体性能。 58 | 59 | 参考: 60 | - [图形处理器 - 百度百科](https://baike.baidu.com/item/%E5%9B%BE%E5%BD%A2%E5%A4%84%E7%90%86%E5%99%A8/8694767?fromtitle=gpu&fromid=105524) 61 | 62 | #### 3.3 GPU 和 CPU 的区别? 63 | 64 | 65 | 参考: 66 | - [CPU 和 GPU 的区别是什么?](https://www.zhihu.com/question/19903344) 67 | 68 | #### 3.4 GPU 的工作原理 69 | 70 | 71 | 参考: 72 | - [CPU 和 GPU 的区别是什么?](https://www.zhihu.com/question/19903344) 73 | 74 | #### 3.5 GPU 和显卡的关系 75 | 76 | GPU 是显卡的主要处理单元。GPU是显示卡的“大脑”,GPU决定了该显卡的档次和大部分性能,同时GPU也是2D显示卡和3D显示卡的区别依据。 77 | 78 | GPU 使显卡减少了对中央处理器的依赖,并分担了部分原本是由中央处理器所担当的工作,尤其是在进行三维绘图运算时,功效更加明显。 79 | 80 | 参考: 81 | - [GPU 和显卡是什么关系?](https://www.zhihu.com/question/28422454) 82 | - [图形处理器 - 维基百科](https://zh.wikipedia.org/wiki/%E5%9C%96%E5%BD%A2%E8%99%95%E7%90%86%E5%99%A8) 83 | 84 | 85 | ### 4. 像素和颜色 86 | 87 | - 像素布局 88 | - ARGB 89 | - YCbCr 90 | 91 | ### 5. 图片格式 92 | 93 | - 显示一张图片需要经历几个步骤:读取图片数据、解压缩、像素对齐、渲染显示 94 | - png 图片是无损压缩的,png 图片比 jpg 图片的解码效率更高 95 | - png 有 alpha 通道,jpg 没有 96 | - Xcode 会把 png 图片进行解码优化之后引入工程 97 | - 如果一张图片具有轮廓形状规则、大量内容重复、背景纯色的特点(也就是说尺寸伸缩不会影响显示效果),我们可以通过加载小图来拉伸的方式来实现大图的效果(比如聊天气泡)。因为更小的图片占用更少的内存,解码也会更快。 98 | 99 | ### 6. iOS 上的图像绘制架构 100 | 101 | ![](https://www.objccn.io/images/issues/issue-3/pixels-software-stack.png) 102 | 103 | 屏幕图像的显示依赖于 GPU 合成的位图/纹理,软件层通过 GPU Driver 跟 GPU 硬件打交道。OpenGL(Open Graphics Library) 提供了 2D 和 3D 图形渲染的 API,自从 OpenGL 的出现,程序员不再需要为每个GPU重写他们的应用了。基于 OpenGL,Apple 通过 Core Animation、Core Graphics 和 Core Image 等框架实现了更高层次的图像绘制功能。提供了更友好的 API。 104 | 105 | ![](https://www.objccn.io/images/issues/issue-3/pixels%2C%20hardware.png) 106 | 107 | 从 CPU 到 GPU 要面临的两个挑战: 108 | 109 | - 为了让 GPU 访问数据,需要将数据从 RAM 移动到 VRAM 上。这看起来貌似微不足道,但是一些大型的纹理却会非常耗时。 110 | - GPU 需要将每一个 frame 的纹理(位图)合成在一起(60次/秒)。每一个纹理会占用 VRAM(video RAM),所以需要给 GPU 同时保持纹理的数量做一个限制。GPU 在合成方面非常高效,但是某些合成任务却比其他更复杂,并且 GPU在 16.7ms(1/60s)内能做的工作也是有限的。 111 | 112 | ## 二、图像显示原理 113 | 114 | 115 | ### 1. View 是如何显示到屏幕上的 116 | 117 | 118 | #### 1.1 图像显示原理 119 | 120 | ![](https://blog.ibireme.com/wp-content/uploads/2015/11/ios_screen_display.png) 121 | 122 | CRT 显示屏在显示图像时,会有一个电子枪从上到下逐行扫描。为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号,分别是水平同步信号(horizonal synchronization,简称 HSync)和垂直同步信号(vertical synchronization,简称 VSync)。 123 | 124 | 计算机显示图像的过程是由 CPU、GPU 和显示器三者协同合作实现的,CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。 125 | 126 | 现在的显示系统通常会引入两个缓冲区,即双缓冲机制,双缓冲机制带来了画面撕裂(Screen Tearing)的问题,所以,为了解决这个问题,GPU 通常有一个机制叫做垂直同步(简写也是 V-Sync),当开启垂直同步后,GPU 会等待显示器的 VSync 信号发出后,才进行新的一帧渲染和缓冲区更新。 127 | 128 | 129 | #### 1.2 卡顿产生的原因 130 | 131 | ![](https://blog.ibireme.com/wp-content/uploads/2015/11/ios_frame_drop.png) 132 | 133 | 图像是如何从代码显示到屏幕上的: 134 | 135 | ① iOS 图形服务收到显示器发出的 VSync 信号后(每秒钟 60 次),会通过 IPC 通知到 App 内,App 的 Runloop 再回调要显示的 view 进行绘制和调整。 136 | ② App 主线程开始在 CPU 中计算好显示内容,比如视图的创建、布局计算、图片解码、文本绘制等; 137 | ③ 随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU 进行变换、合成、渲染; 138 | ④ 接着,GPU 会把渲染结果提交到帧缓冲区,等待下一次 VSync 信号到来时显示到屏幕上; 139 | 140 | 141 | 由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。 142 | 143 | **参考:** 144 | 145 | - [绘制像素到屏幕上 - objc.io](https://www.objccn.io/issue-3-1/)(推荐) 146 | - [iOS 保持界面流畅的技巧](https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/)(推荐) 147 | 148 | ### 2. 合成(Compositing) 149 | 在图形世界中,合成是一个描述不同位图如何放到一起来创建你最终在屏幕上看到图像的过程。 150 | 151 | 让我们先暂时忽略一些复杂的细节,并且假定屏幕上一切皆纹理。一个纹理就是一个包含 RGBA 值的长方形,比如,每一个像素里面都包含红、绿、蓝和透明度的值。在 Core Animation 世界中这就相当于一个 CALayer。 152 | 153 | 在这个简化的设置中,每一个 layer 是一个纹理,所有的纹理都以某种方式堆叠在彼此的顶部。对于屏幕上的每一个像素,GPU 需要算出怎么混合这些纹理来得到像素 RGB 的值。这就是合成大概的意思。 154 | 155 | ### 3. 混合(Blending):透明 VS 不透明 156 | - 当源纹理是完全不透明的时候,目标像素就等于源纹理。这可以省下 GPU 很大的工作量,这样只需简单的拷贝源纹理而不需要合成所有的像素值。 157 | 158 | - CALayer 有一个叫做 opaque 的属性了。如果这个属性为 YES,GPU 将不会做任何合成,而是简单从这个层拷贝,不需要考虑它下方的任何东西(因为都被它遮挡住了)。这节省了 GPU 相当大的工作量。 159 | 160 | - 如果你知道你的 layer 是不透明的,最好确定设置它的 opaque 为 YES(UIView 的 backgroundColor 同理)。如果你加载一个没有 alpha 通道的图片,并且将它显示在 UIImageView 上,这将会自动发生。也就是说,如果你用 UIImageView 来显示一张有 alpha 通道的图片,也会导致 blending,即使你设置了 `imageView.backgroundColor = YES;`。 161 | 162 | - 在iOS模拟器上运行App,在模拟器的菜单中选择`Debug`,然后选中`Color Blended Layers`。然后iOS模拟器就会将全部区域显示为两种颜色:绿色和红色。绿色区域没有混合,但红色区域表示有混合操作。 163 | 164 | ### 4. 像素对齐(Pixel Alignment) 165 | 166 | 167 | 在 iOS 中,有一个概念叫做像素对齐,如果像素不对齐,那么在GPU渲染时,需要进行插值计算,这个插值计算的过程会有性能损耗。 168 | 169 | 主要有两个原因可能会造成不对齐: 170 | 171 | - 第一个便是缩放,当一个纹理放大缩小的时候,纹理的像素便不会和屏幕的像素排列对齐。 172 | - 比如在 iPhone 6 上,一张 400 * 500 像素的图片在一个 200 * 252 pt (物理像素为 400 * 504 pixel)或者 100 * 125 pt(物理像素为 200 * 250 pixel)的 UIImageView 中展示时,就会出现像素不对齐的情况。 173 | - 另一个原因便是当纹理的起点不在一个像素的边界上。 174 | - 比如设置一个 UILabel 的 frame 为 `CGRectMake(100.03, 494.0, 197.0, 76.0)` 时,就会出现像素不对齐的情况,因为 x 坐标乘以 2 或者 3 之后都会有小数部分。 175 | 176 | 177 | 在这两种情况下,GPU 需要再做额外的计算。它需要将源纹理上多个像素混合起来,生成一个用来合成的值。当所有的像素都是对齐的时候,GPU 只剩下很少的工作要做。 178 | 179 | 在 iPhone 模拟器和 Instruments 上,有一个 `color misaligned images` 选项可以把像素不对齐的部分显示出来。当 UIView(及其子类)的frame像素不对齐显示洋红色;当图片的像素大小与控件的大小不一致而导致需要缩放时,显示黄色。 180 | 181 | 延伸阅读: 182 | 183 | - [iOS优化:解决iOS中像素不对齐问题](https://www.jianshu.com/p/432fea0232b8) 184 | - [iOS开发之图片分辨率与像素对齐](https://www.cnblogs.com/huahuahu/p/iOS-kai-fa-zhi-tu-pian-fen-bian-lu-yu-xiang-su-dui.html) 185 | 186 | ### 5. CALayer 的 Mask 187 | 188 | Mask 属性本身也是一个 CALayer。不同于那些绘制在父图层中的 sublayer,mask 图层定义了父图层的部分可见区域。 189 | 190 | mask图层的Color属性是无关紧要的,真正重要的是图层的轮廓。mask属性就像是一个饼干切割机,mask图层实心的部分会被保留下来,其他的则会被抛弃。也就是说,父图层中只有在 mask 范围内的(即图层中的部分)内容才会被渲染出来。 191 | 192 | 参考: 193 | 194 | - [Mask - iOS Core Animation Advanced Techniques](https://zsisme.gitbooks.io/ios-/content/chapter4/layer-masking.html) 195 | 196 | 197 | ### 4. 光栅化 198 | 199 | 光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。 200 | 201 | 在 Xcode 9 中,找到菜单 Debug->View Debugging->Rendering, 其中有一个调试选项是`Color Hits Green and Misses Red`,它表示如果命中缓存则显示为绿色,否则显示为红色,显然绿色越多越好,红色越少越好。 202 | 203 | 当设置 `view.layer.shouldRasterize = YES` 时,耗时的图片绘制会被缓存,并当做一个简单的扁平图片来呈现。需要注意的是,缓存中的对象有效期只有100ms,即如果在0.1s内没有被使用就会自动从缓存中清理出去。因为栅格化生成缓存的过程是有开销的,如果缓存能被大量命中和有效使用,则总体上会降低开销,反之则意味着要频繁生成新的缓存,这会让性能问题雪上加霜。因此光栅化仅适用于经常使用的、较复杂的、静态的效果。 204 | 205 | ### 5. 离屏渲染(Offscreen Rendering) 206 | 207 | #### 5.1 什么是离屏渲染 208 | 209 | 离屏渲染一般是指 GPU 在当前屏幕缓冲区以外新开辟一个缓冲区进行合成、渲染操作,然后再渲染到屏幕上。离屏渲染可以被 Core Animation 或者系统自动触发。 210 | 211 | 当图像合成计算非常复杂时,你也可以手动强制使用离屏渲染——将合成好的图层或者纹理缓存起来,然后当再次需要显示这些图层时,就可以读取这些缓存了。你可以通过设置 shouldRasterize 为 YES 来触发这个行为。 212 | 213 | 但是,这其实也需要权衡一下。第一,这可能会使事情变得更慢。创建额外的屏幕外缓冲区是 GPU 需要多做的一步操作,特殊情况下这个位图可能再也不需要被复用,这便是一个无用功了。另外,可以被复用的位图,GPU 也有可能将它卸载了。所以你需要计算 GPU 的利用率和帧的速率来判断这个位图是否有用。 214 | 215 | 216 | #### 5.2 离屏渲染所带来的问题 217 | 相比于当前屏幕渲染,离屏渲染的代价是很高的,主要体现在两个方面: 218 | 219 | (1)创建新缓冲区 220 | 要想进行离屏渲染,首先要创建一个新的缓冲区。 221 | 222 | (2)上下文切换 223 | 离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上有需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。 224 | 225 | #### 5.3 哪些情况可能会导致 Offscreen Render 呢? 226 | 227 | - `layer.shouldRasterize = YES;` 228 | - 设置 mask 或者阴影 229 | - masksToBounds(但是最新的试验中却没有产生离屏渲染,iOS 11,Xcode 9.3) 230 | - masks(遮罩) 231 | - shadows(阴影) 232 | - edge antialiasing(抗锯齿) 233 | - group opacity(不透明) 234 | - 重写 `-drawRect` 方法 235 | - 这是一种特殊的“离屏渲染”方式,如果我们重写了drawRect方法,并且使用任何 Core Graphics 的技术进行了绘制操作,就涉及到了 **CPU 渲染**。整个渲染过程由 CPU 在App内同步地完成,渲染得到的 bitmap 最后再交给 GPU 去显示。 236 | 237 | > 设置cornerRadius本身并不会导致离屏渲染,但很多时候它还需要配合 `layer.masksToBounds = YES` 使用,正是因为操作了 mask 才导致的离屏渲染。 238 | 239 | #### 5.4 如何避免离屏渲染 240 | 241 | - 设置阴影:通过设置 layer 的 shadowPath 属性来设置阴影的路径,如果没有手动指定,Core Animation会去自动计算,这就会触发离屏渲染。 242 | - 设置圆角(分两种情况): 243 | - 设置 UIImageView 的圆角:先通过 Core Graphics 结合 UIBezierPath 将原图片(UIImage)裁剪成圆角形式的图片,然后再赋值给 UIImageView 的 image 属性。这个过程其实可以异步执行并且缓存起来,具体实现可以参考 [YYKit](https://github.com/ibireme/YYKit/blob/master/Demo/YYKitDemo/WBStatusCell.m#L757) 中的 demo。 244 | - 设置其他非图片展示类型的 UIView 的圆角:创建一个圆角矩形的 CAShapeLayer,然后再添加到 view.layer 的最底层,具体代码见 [这里](https://zsisme.gitbooks.io/ios-/content/chapter15/offscreen-rendering.html)。或者用 Core Graphics 的 API 绘制一个圆角矩形图片,然后再基于这个图片创建一个 UIImageView,最后再添加到 view 层级的最底层。 245 | 246 | 参考: 247 | 248 | - [iOS 高效添加圆角效果实战讲解](https://bestswifter.com/efficient-rounded-corner/) 249 | 250 | #### 5.5 当前屏幕渲染 VS 离屏渲染 VS CPU 渲染 251 | 252 | - 当屏渲染永远是最好的选择 253 | - 鉴于离屏渲染、CPU渲染可能带来的性能问题,一般情况下,我们要尽量使用当前屏幕渲染。 254 | - 离屏渲染 VS CPU 渲染 255 | - 由于GPU的浮点运算能力比CPU强,CPU渲染的效率可能不如离屏渲染;但如果仅仅是实现一个简单的效果,直接使用CPU渲染的效率又可能比离屏渲染好,毕竟离屏渲染要涉及到缓冲区创建和上下文切换等耗时操作。而且 CPU 上还可以使用异步绘制。 256 | 257 | 258 | 既然绘图性能是基于 CPU 和 GPU 的,那么你需要找出是哪一个限制你绘图性能的。如果你用尽了 GPU 所有的资源,也就是说,是 GPU 限制了你的性能,同样的,如果你用尽了 CPU,那就是 CPU 限制了你的性能。 259 | 260 | #### 5.6 调试检测 261 | Instrument 的 Core Animation 工具有一个叫做 Color Offscreen-Rendered Yellow 的选项,它会将已经被渲染到屏幕外缓冲区的区域标注为黄色(这个选项在模拟器中也可以用)。 262 | 263 | 264 | ### 6. Core Animation 和 CALayer 265 | 266 | #### 6.1 Core Animation 267 | 268 | ![](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/Art/ca_architecture_2x.png) 269 | 270 | Core Animation 是专门处理图形渲染和动画的基础框架. 271 | 272 | 273 | Core Animation 的核心是 OpenGL ES 的一个抽象物,简而言之,它让你直接使用 OpenGL ES 的功能,却不需要处理 OpenGL ES 做的复杂的事情。 274 | 275 | Core Animation 的 layer 可以有子 layer,所以最终你得到的是一个图层树。Core Animation 所需要做的最繁重的任务便是判断出哪些图层需要被(重新)绘制,而 OpenGL ES 需要做的便是将图层合并、显示到屏幕上。 276 | 277 | 当你设置一个 layer 的内容为一个 CGImageRef 对象时,Core Animation 会创建一个 OpenGL 纹理,并确保在这个图片中的位图数据会被上传到对应的纹理中。还有当你重写 `-drawInContext:` 方法时,Core Animation 会请求分配一个纹理,同时确保你通过调用 Core Graphics 的 API 绘制的内容(即你在`drawInContext:` 中绘制的东西)会转换到纹理的位图数据中。 278 | 279 | 一个 layer 的属性和你所选用的 CALayer 子类的类型都将会影响到 OpenGL 的渲染过程,许多底层的 OpenGL ES 的 API 都被封装到 Core Animation 中,以更友好地形式展现了。 280 | 281 | Core Animation 通过将一端的 Core Graphics 和另一端的 OpenGL ES 串联起来实现了基于 CPU 的位图绘制。 282 | 283 | #### 6.2 CALayer 284 | 285 | 286 | 287 | ### 7. Core Graphics / Quartz 2D 288 | 289 | Quartz 2D 是一个 2D 绘图引擎,提供了底层的、轻量的渲染功能。当 iOS 应用进行位图绘制时,不管使用哪种方式,都是基于 Quartz 2D 的。也就是说,CPU 部分实现的绘制是通过 Quartz 2D 实现的。 290 | 291 | Quartz 2D 可以做的事: 292 | 293 | - transparency layers 294 | - path-based drawing 295 | - offscreen rendering 296 | - advanced color management 297 | - anti-aliased rendering 298 | - PDF document creation 299 | - display 300 | - parsing 301 | 302 | Quartz 2D 在进行绘制时,需要现提供一个 Graphics Context,这个 Context 定义了我们需要绘制的地方。当我们在实现 `CALayer` 的 `-drawInContext:` 方法时,我们要绘制的内容就传给了这个 Context 参数,绘制到 Context 上后接下来就会绘制到这个 layer 的 backing store (缓存区)上。 303 | 304 | ### 8. `–drawRect:` 305 | 306 | 每个 UIView 都有一个 CALayer,这个 CALayer 一般会有一个对应的 backing store,其实也就是一个位图(类似于图片)。最终要显示到屏幕上的就是这个 backing store。 307 | 308 | #### 8.1 `-drawRect:` 方法的工作流程 309 | 310 | 如果你的视图类实现了 `-drawRect:`,他们将像这样工作: 311 | > Core Animation 在 RunLoop 中注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件 。当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView 的 setNeedsLayout 方法后,这个 UIView 就被标记为待处理,并被提交到一个全局的容器去。 312 | > 313 | > 当Oberver监听的事件到来时,回调执行函数中会遍历所有待处理的 UIView,并调用它们的 layer 的 `display` 方法。这个时候,layer 就会配置好它们自己的 backing store,接下来就可以从这个 backing store 的内存中获取一个 Core Graphics 上下文(CGContextRef)用来绘制,在这个上下文中绘制了内容后,又会重新写入这个 backing store 的内存中,并最终会被显示到屏幕上。 314 | 315 | 下面是 `-drawRect:`方法的调用栈: 316 | 317 | ``` 318 | frame #0: 0x0000000103089807 YHMainApp`-[YHMembershipLevelProgressView drawRect:](self=0x00007ffaaf49f3b0, _cmd="drawRect:", rect=(origin = (x = 0, y = 0), size = (width = 560, height = 26))) at YHMembershipLevelProgressView.m:70 319 | frame #1: 0x000000010a271df0 UIKit`-[UIView(CALayerDelegate) drawLayer:inContext:] + 600 320 | frame #2: 0x0000000109b2d242 QuartzCore`-[CALayer drawInContext:] + 305 321 | frame #3: 0x0000000109a3ba48 QuartzCore`CABackingStoreUpdate_ + 254 322 | frame #4: 0x0000000109b33464 QuartzCore`___ZN2CA5Layer8display_Ev_block_invoke + 44 323 | frame #5: 0x0000000109b2cd56 QuartzCore`-[CALayer _display] + 2013 324 | frame #6: 0x0000000109ab83c2 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 634 325 | frame #7: 0x0000000109ae5940 QuartzCore`CA::Transaction::commit() + 568 326 | frame #8: 0x0000000109ae66be QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 76 327 | frame #9: 0x000000010e2ca607 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23 328 | frame #10: 0x000000010e2ca55e CoreFoundation`__CFRunLoopDoObservers + 430 329 | frame #11: 0x000000010e2aeb81 CoreFoundation`__CFRunLoopRun + 1537 330 | frame #12: 0x000000010e2ae30b CoreFoundation`CFRunLoopRunSpecific + 635 331 | frame #13: 0x000000010fe89a73 GraphicsServices`GSEventRunModal + 62 332 | frame #14: 0x000000010a1a30b7 UIKit`UIApplicationMain + 159 333 | frame #15: 0x00000001026f099f YHMainApp`main(argc=1, argv=0x00007ffeed51a078) at main.m:14 334 | frame #16: 0x000000010f130955 libdyld.dylib`start + 1 335 | frame #17: 0x000000010f130955 libdyld.dylib`start + 1 336 | ``` 337 | 338 | #### 8.2 使用图片而不是重写 `-drawRect:` 方法 339 | 340 | 当我们直接使用一个 UIImageView 显示一张图片,而不是实现 `-drawRect:` 方法时,imageView 的 layer 不会申请一个 backing store,而是设置 layer 的 content 属性(一个 CGImageRef),并且 render server 将会把图片的位图数据绘制到帧的缓冲区,比如,绘制到显示屏。 341 | 342 | 在这种情况下,就不存在图形绘制的逻辑了,我们只是简单地把一张图片的位图数据传给 UIImageView,这个 UIImageView 又将数据转发给 Core Animation,最后 Core Animation 又将这些数据交给 render server 去渲染、显示。 343 | 344 | #### 8.3 到底要不要去重写 `-drawRect:` 方法 345 | 346 | 大多数情况下,通过组合 Apple 框架提供的 views 或者 layers 就可以实现自定义 view。这也是非常推荐的一种做法,因为 UIKit 中 view 相关的类都已经经过了极度优化的。所以,如果没有必要,最好避免通过实现 `-drawRect:` 方法去绘制。 347 | 348 | 在某些情况下,自定义绘图也并不需要去重写 `-drawRect:` 方法,一个更好的方式是,通过调用 `UIGraphicsBeginImageContextWithOptions()` 函数或者 `CGBitmapContextCeate()` 函数去创建一个位图,然后从位图上面获取 image,并设置为 CALayer 的 content。 349 | 350 | > 即便你在重写的 `-drawRect:` 方法中什么都没有做,这也会耗费一定的资源。因为这会促使 Core Animation 为我们创建一个 backing store,然后上传给 GPU。 351 | 352 | 353 | ### 9. 异步绘制 354 | 355 | ## 三、优化技巧(Tips) 356 | 357 | 优化的关键在于平衡 CPU 和 GPU 的负担,你需要清楚地知道哪部分渲染需要使用GPU,哪部分可以使用CPU,以保持平衡。 358 | 359 | ### CPU 360 | 361 | - 减低对象的创建的成本 362 | - 尽量用轻量的对象代替重量的对象,比如当展示不要响应触摸事件的视图时,用 CALayer 而不是 UIView 363 | - 如果对象可以复用,并且复用的代价比释放、创建新对象要小,那么这类对象应当尽量放到一个缓存池里复用 364 | - 在性能要求高的情况下,避免使用 storyboard/xib 365 | - 布局优化 366 | - 在后台线程提前计算好视图布局、并且对视图布局进行缓存,比如 UITableViewCell 高度的计算就可以这么做 367 | - 尽量使用代码手动计算,而不是通过 xib/storyboard 加 autolayout 来实现 368 | - 复用 UITableViewCell/UICollectionViewCell 369 | - 图片解码 370 | - 在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片。目前常见的网络图片库都自带这个功能。(因为要等到 CALayer 被提交到 GPU 前,CGImage 中的数据才会得到解码) 371 | - 文本处理 372 | - 文本宽高计算:参考 UILabel 内部的实现方式来计算文本宽高,更进一步地,可以放到后台线程进行计算,以避免阻塞主线程 373 | - 文本渲染:当需要显示大量文本时,可通过自定义文本控件,用 TextKit 或最底层的 CoreText 对文本异步绘制。 374 | - 异步绘制 375 | - 由于 Core Graphic 方法通常都是线程安全的,所以一些复杂图像的绘制可以很容易的放到后台线程进行,等到绘制完毕后再生成图片来展示 376 | - 设置 CALayer 的 `drawsAsynchronously` 属性为YES 377 | 378 | ### GPU 379 | 380 | > 相对于 CPU 来说,GPU 能干的事情比较单一:接收提交的纹理(Texture)和顶点描述(三角形),应用变换(transform)、混合并渲染,然后输出到屏幕上。通常你所能看到的内容,主要也就是纹理(图片)和形状(三角模拟的矢量图形)两类。 381 | 382 | - 减少混合 383 | - 尽量将背景色设置成不透明(通过设置 UIView 的 opaque 属性或者 backgroundColor 属性来调整) 384 | - 减少 view/layer 的层级数量 385 | - 将多个 view 合成一张图片来显示 386 | - 避免像素对齐 387 | - 对所有像素相关的数据做取整处理,包括点坐标,UIView的高度和宽度。 388 | - 尽量保持图片的像素尺寸大小和要显示的 view 大小一致。 389 | - 防止离屏渲染 390 | - 对于只需要圆角的某些场合,也可以用一张已经绘制好的圆角图片覆盖到原本视图上面来模拟相同的视觉效果。最彻底的解决办法,就是把需要显示的图形在后台线程绘制为图片,避免使用圆角、阴影、遮罩等属性。 391 | - 纹理的渲染 392 | - 尽量减少在短时间内大量图片的显示,尽可能将多张图片合成为一张进行显示。(这是因为,所有的 Bitmap,包括图片、文本、栅格化的内容,最终都要由内存提交到显存,绑定为 GPU Texture。不论是提交到显存的过程,还是 GPU 调整和渲染 Texture 的过程,都要消耗不少 GPU 资源。) 393 | - 控制图片和视图的大小。当图片过大,超过 GPU 的最大纹理尺寸时,图片需要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗。 394 | 395 | ## 参考 396 | - [计算机图形渲染的流程](https://bbs.feng.com/read-htm-tid-6880069.html) 397 | - [绘制像素到屏幕上 - objc.io](https://www.objccn.io/issue-3-1/)(推荐) 398 | - [iOS 保持界面流畅的技巧](https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/)(推荐) 399 | - [iOS图形渲染分析](https://www.jianshu.com/p/77d0cb17cfad) 400 | - [UIKit性能调优实战讲解](https://bestswifter.com/uikitxing-neng-diao-you-shi-zhan-jiang-jie/) 401 | - [深刻理解移动端优化之离屏渲染](https://www.jianshu.com/p/d74398c50fe1) 402 | - [iOS Core Animation: Advanced Techniques](https://zsisme.gitbooks.io/ios-/content/chapter14/caching.html)(推荐) 403 | - [使用 Instruments 做 iOS 程序性能调试](http://www.samirchen.com/use-instruments/) 404 | - [深入理解RunLoop](https://blog.ibireme.com/2015/05/18/runloop/)(推荐) 405 | - [Perfect Smooth Scrolling in UITableViews](https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5)([中文翻译](https://southpeak.github.io/2015/12/20/perfect-smooth-scrolling-in-uitableviews/)) 406 | - [UITableView优化技巧](http://www.cocoachina.com/ios/20150602/11968.html)([VVeboTableViewDemo](https://github.com/johnil/VVeboTableViewDemo)) 407 | - [iOS图片加载速度极限优化—FastImageCache解析](https://blog.cnbang.net/tech/2578/) 408 | - [Mastering Offscreen Render](https://github.com/seedante/iOS-Note/wiki/Mastering-Offscreen-Render) 409 | 410 | ## WWDC 411 | - [WWDC 2011 - Session 121: Understanding UIKit Rendering](https://developer.apple.com/videos/play/wwdc2011/121/) 412 | - [WWDC 2014 - Session 419: Advanced Graphics and Animations for iOS Apps](https://developer.apple.com/videos/play/wwdc2014/419/) 413 | - [WWDC 2011 - Session 129: Practical Drawing for iOS Developers](https://developer.apple.com/videos/play/wwdc2011/129/) 414 | - [WWDC 2012 - Session 506: Optimizing 2D Graphics and Animation Performance](https://developer.apple.com/videos/play/wwdc2012/506/) 415 | - [WWDC 2012 - Session 211: Building Concurrent User Interfaces on iOS](https://developer.apple.com/videos/play/wwdc2012/211/) 416 | --------------------------------------------------------------------------------