{"id":59899,"date":"2019-02-06T04:20:33","date_gmt":"2019-02-06T11:20:33","guid":{"rendered":"http:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/"},"modified":"2019-02-06T04:20:33","modified_gmt":"2019-02-06T11:20:33","slug":"ios-performance-tricks-to-make-your-app-feel-more-performant","status":"publish","type":"post","link":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/","title":{"rendered":"iOS Performance Tricks To Make Your App Feel More Performant"},"content":{"rendered":"<link rel=\"canonical\" href=\"https:\/\/www.smashingmagazine.com\/2019\/02\/ios-performance-tricks-apps\/\"><title>iOS Performance Tricks To Make Your App Feel More Performant<\/title><\/p>\n<article>\n<header>\n<h1>iOS Performance Tricks To Make Your App Feel More Performant<\/h1>\n<address>Axel Kee<\/address>\n<p>                  <time datetime=\"2019-02-05T13:00:00+01:00\">2019-02-05T13:00:00+01:00<\/time><time datetime=\"2019-02-06T11:12:17+00:00\">2019-02-06T11:12:17+00:00<\/time><\/header>\n<p>Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we will look into five optimization tricks that will make your app feel more responsive.<\/p>\n<h3>1. Dequeue Reusable Cell<\/h3>\n<p>You\u2019ve probably used <code>tableView.dequeueReusableCell(withIdentifier:for:)<\/code>  inside <code>tableView(_:cellForRowAt:)<\/code> before. Ever wondered why you have to follow this awkward API, instead of just passing an array of cell in? Let\u2019s go through the reasoning of this.<\/p>\n<p>Say you have a table view with a thousand rows. Without using reusable cells, we would have to create a new cell for each row, like this:<\/p>\n<pre><code>func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n   \/\/ Create a new cell whenever cellForRowAt is called.\n   let cell = UITableViewCell()\n   cell.textLabel?.text = \"Cell (indexPath.row)\"\n   return cell\n}\n<\/code><\/pre>\n<p>As you might have thought, this will add a thousand cells to the device\u2019s memory as you scroll to the bottom. Imagine what would happen if each cell contained a <code>UIImageView<\/code> and a lot of text: Loading them all at once could cause the app to run out of memory! Apart from that, every single cell would require new memory to be allocated during scrolling. If you scroll a table view quickly, a lot of small chunks of memory will be allocated on the fly, and this process will make the UI janky!<\/p>\n<p>To resolve this, Apple has provided us with the <code>dequeueReusableCell(withIdentifier:for:)<\/code> method. Cell reuse works by placing the cell that is no longer visible on the screen into a queue, and when a new cell is about to be visible on the screen (say, the subsequent cell below as the user scrolls down), the table view will retrieve a cell from this queue and modify it in the <code>cellForRowAt indexPath:<\/code> method.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-1-dequeue.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-1-dequeue.png?w=900\" sizes=\"100vw\" alt=\"Cell reuse queue mechanism\"><\/a><figcaption>\n\t\t\tHow cell reuse queues work in iOS (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/ba882cd5-8212-4b68-8ad0-cdbf9e26aeb3\/ios-performance-tricks-1-dequeue.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>By using a queue to store cells, the table view doesn\u2019t need to create a thousand cells. Instead, it needs just enough cells to cover the area of the table view.<\/p>\n<p>By using <code>dequeueReusableCell<\/code>, we can reduce the memory used by the app and make it less prone to running out of memory!<\/p>\n<aside data-audience=\"non-subscriber\">\n<div>\n<div>\n<p>Getting workflow <em>just<\/em> right ain\u2019t an easy task. So are proper estimates. Or alignment among different departments. That\u2019s why we\u2019ve set up <strong>\u201cthis-is-how-I-work\u201d-sessions<\/strong> \u2014 with smart cookies sharing what works well for them. A part of the <a href=\"http:\/\/bit.ly\/2Qy9gcR\">Smashing Membership<\/a>, of course.<\/p>\n<p>      <a href=\"http:\/\/bit.ly\/2Qy9gcR\"><br \/>\n        Explore Smashing Membership\u00a0?<br \/>\n      <\/a>\n      <\/div>\n<div>\n        <a href=\"http:\/\/bit.ly\/2Qy9gcR\"><\/p>\n<div>\n          <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.smashingmagazine.com\/images\/smashing-cat\/smashing-tv-box-cat.svg\" alt=\"Smashing TV, with live sessions for professional designers and developers.\" width=\"310\" height=\"400\"><\/div>\n<p>      <\/a>\n      <\/div>\n<\/p><\/div>\n<\/aside>\n<h3>2. Using A Launch Screen That Looks Like The Initial Screen<\/h3>\n<p>As mentioned in Apple\u2019s <a href=\"https:\/\/developer.apple.com\/design\/human-interface-guidelines\/ios\/icons-and-images\/launch-screen\/\">Human Interface Guidelines<\/a> (HIG), launch screens can be used to enhance the perception of an app\u2019s responsiveness:<\/p>\n<blockquote><p>\u201cIt\u2019s solely intended to enhance the perception of your app as quick to launch and immediately ready for use. Every app must supply a launch screen.\u201d<\/p><\/blockquote>\n<p>It\u2019s a common mistake to use a launch screen as a splash screen to show branding or to add a loading animation. Design the launch screen to be identical to the first screen of your app, as mentioned by Apple:<\/p>\n<blockquote><p>\u201cDesign a launch screen that\u2019s nearly identical to the first screen of your app. If you include elements that look different when the app finishes launching, people can experience an unpleasant flash between the launch screen and the first screen of the app.<\/p>\n<p>\u201cThe launch screen isn\u2019t a branding opportunity. Don\u2019t design an entry experience that looks like a splash screen or an &#8220;About&#8221; window. Don\u2019t include logos or other branding elements unless they\u2019re a static part of your app\u2019s first screen.\u201d<\/p><\/blockquote>\n<p>Using a launch screen for loading or branding purposes could slow down the time of first use and make the user feel that the app is sluggish.<\/p>\n<p>When you start a new iOS project, a blank <code>LaunchScreen.storyboard<\/code> will be created. This screen will be shown to the user while the app loads the view controllers and layout.<\/p>\n<p>To make your app feel faster, you can design the launch screen to be similar to the first screen (view controller) that will be shown to the user.<\/p>\n<p>For example, the Safari app\u2019s launch screen is similar to its first view :<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-2-launchscreen.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-2-launchscreen.png?w=900\" sizes=\"100vw\" alt=\"Launch screen and first view look similar\"><\/a><figcaption>\n\t\t\tA comparison of launch screen and first view of Safari app (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5cf91d55-0418-45e0-8019-3be8f875086e\/ios-performance-tricks-2-launchscreen.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>The launch screen storyboard is like any other storyboard file, except that you can only use the standard UIKit classes, like UIViewController, UITabBarController, and UINavigationController. If you attempt to use any other custom subclasses (such as UserViewController), Xcode will notify you that using custom class names is prohibited.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/04546e45-0976-4fbd-b776-5d720b982bb4\/ios-performance-tricks-3-illegal.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-3.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/526ff784-be5f-4f25-8e04-ce81ef038088\/ios-performance-tricks-3.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/526ff784-be5f-4f25-8e04-ce81ef038088\/ios-performance-tricks-3.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/526ff784-be5f-4f25-8e04-ce81ef038088\/ios-performance-tricks-3.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/526ff784-be5f-4f25-8e04-ce81ef038088\/ios-performance-tricks-3.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-3.png?w=900\" sizes=\"100vw\" alt=\"Xcode shows error when a custom class is used\"><\/a><figcaption>\n\t\t\tLaunch screen storyboard cannot contain non-UIKit standard class. (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/04546e45-0976-4fbd-b776-5d720b982bb4\/ios-performance-tricks-3-illegal.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>Another thing to note is that <code>UIActivityIndicatorView<\/code> doesn\u2019t animate when placed on the launch screen, because iOS will generate a static image from the launch screen storyboard and displays it to the user. (This is mentioned briefly in the WWDC 2014 presentation \u201c<a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2014\/102\/\">Platforms State of the Union<\/a>\u201d, around <code>01:21:56<\/code>.)<\/p>\n<p>Apple\u2019s HIG also advises us not to include text on our launch screen, because the launch screen is static, and you can\u2019t localize text to cater to different languages.<\/p>\n<p><strong>Recommended reading<\/strong>: <em><a href=\"https:\/\/www.smashingmagazine.com\/2018\/02\/mobile-app-facial-recognition-feature\/\">Mobile App With Facial Recognition Feature: How To Make It Real<\/a><\/em><\/p>\n<h3>3. State Restoration For View Controllers<\/h3>\n<p>State preservation and restoration allow the user to return to the exact same UI state from just before they left the app. Sometimes, due to insufficient memory, the operating system might need to remove your app from memory while the app is in the background, and the app might lose track of its last UI state if it is not preserved, possibly causing users to lose their work in progress!<\/p>\n<p>In the multitasking screen, we can see a list of apps that have been put in the background. We might assume that these apps are still running in the background; in reality, some of these apps might get killed and restarted by the system due to the demands of memory. The app snapshots we see in the multitasking view are actually screenshots taken by the system from right when we exited the app (i.e. to go to the home or multitasking screen).<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-4-multitask.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-4-multitask.png?w=900\" sizes=\"100vw\" alt=\"iOS fabricates the illusion of apps running in the background by taking a screenshot of the most recent view\"><\/a><figcaption>\n\t\t\tScreenshots of apps taken by iOS when user exits the app (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/2edd59aa-1195-40cd-8322-7f71a5e2e91b\/ios-performance-tricks-4-multitask.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>iOS uses these screenshots to give the illusion that the app is still running or is still displaying this particular view, whereas the app might have been already terminated or restarted in the background while still displaying the same screenshot.<\/p>\n<div><\/div>\n<p>Have you ever experienced, upon resuming an app from the multitasking screen, that the app shows a user interface different from the snapshot shown in the multitasking view? This is because the app hasn\u2019t implemented the state-restoration mechanism, and the displayed data was lost when the app was killed in the background. This can lead to a bad experience because the user expects your app to be in the same state as when they left it.<\/p>\n<p>From Apple\u2019s <a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/view_controllers\/preserving_your_app_s_ui_across_launches?language=objc\">article<\/a>:<\/p>\n<blockquote><p>\u201cThey expect your app to be in the same state as when they left it. State preservation and restoration ensures that your app returns to its previous state when it launches again.\u201d<\/p><\/blockquote>\n<p>UIKit does a lot of work to simplify state preservation and restoration for us: It handles the saving and loading of an app\u2019s state automatically at appropriate times. All we need to do is add some configuration to tell the app to support state preservation and restoration and to tell the app what data needs to be preserved.<\/p>\n<p>To enable state saving and restoring, we can implement these two methods in <code>AppDelegate.swift<\/code>:<\/p>\n<div>\n<pre><code>func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {\n   return true\n}\n<\/code><\/pre>\n<\/div>\n<div>\n<pre><code>func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {\n   return true\n}\n<\/code><\/pre>\n<\/div>\n<p>This will tell the app to save and restore the application\u2019s state automatically.<\/p>\n<p>Next, we\u2019ll tell the app which view controllers need to be preserved. We do this by specifying the \u201cRestoration ID\u201d in the storyboard :<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-5-restorationid.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-5-restorationid.png?w=900\" sizes=\"100vw\" alt=\"Setting restoration ID in storyboard\"><\/a><figcaption>\n\t\t\tSetting restoration ID in storyboard (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0eb257d5-cd70-4a0b-9565-3782999b9926\/ios-performance-tricks-5-restorationid.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>You can also check \u201cUse Storyboard ID\u201d to use the storyboard ID as the restoration ID.<\/p>\n<p>To set the restoration ID in the code, we can use the <code>restorationIdentifier<\/code> property of the view controller.<\/p>\n<pre><code>\/\/ ViewController.swift\nself.restorationIdentifier = \"MainVC\"\n<\/code><\/pre>\n<p>During state preservation, any view controller or view that has been assigned a restoration identifier will have its state saved to disk.<\/p>\n<p>Restoration identifiers can be grouped together to form a restoration path. The identifiers are grouped using the view hierarchy, from the root view controller to the current active view controller. Suppose a MyViewController is embedded in a navigation controller, which is embedded in another tab bar controller. Assuming they are using their own class names as restoration identifiers, the restoration path will look like this:<\/p>\n<pre><code>TabBarController\/NavigationController\/MyViewController\n<\/code><\/pre>\n<p>When the user leaves the app with the MyViewController being the active view controller, this path will be saved by the app; then the app will remember the previous view hierarchy shown (<em>Tab Bar Controller<\/em> ? <em>Navigation Controller<\/em> ? <em>My View Controller<\/em>).<\/p>\n<p>After assigning the restoration identifier, we will need to implement the encodeRestorableState(with coder:) and decodeRestorableState(with coder:) methods for each of the preserved view controllers. These two methods let us specify what data need to be saved or loaded and how to encode or decode them.<\/p>\n<p>Let\u2019s see the view controller:<\/p>\n<div>\n<pre><code>\/\/ MyViewController.swift\n?\n\/\/ MARK: State restoration\n\/\/ UIViewController already conforms to UIStateRestoring protocol by default\nextension MyViewController {\n\n   \/\/ will be called during state preservation\n   override func encodeRestorableState(with coder: NSCoder) {\n       \/\/ encode the data you want to save during state preservation\n       coder.encode(self.username, forKey: \"username\")\n       super.encodeRestorableState(with: coder)\n   }\n   \n   \/\/ will be called during state restoration\n   override func decodeRestorableState(with coder: NSCoder) {\n     \/\/ decode the data saved and load it during state restoration\n     if let restoredUsername = coder.decodeObject(forKey: \"username\") as? String {\n       self.username = restoredUsername\n     }\n     super.decodeRestorableState(with: coder)\n   }\n} \n<\/code><\/pre>\n<\/div>\n<p>Remember to call the superclass implementation at the bottom of your own method. This ensures that the parent class has a chance to save and restore state.<\/p>\n<p>Once the objects have finished decoding, <code>applicationFinishedRestoringState()<\/code> will be called to tell the view controller that the state has been restored. We can update the UI for the view controller in this method.<\/p>\n<div>\n<pre><code>\/\/ MyViewController.swift\n?\n\/\/ MARK: State restoration\n\/\/ UIViewController already conforms to UIStateRestoring protocol by default\nextension MyViewController {\n   ...\n \n   override func applicationFinishedRestoringState() {\n     \/\/ update the UI here\n     self.usernameLabel.text = self.username\n   }\n}\n<\/code><\/pre>\n<\/div>\n<p>There you have it! These are the essential methods to implement state preservation and restoration for your app. Keep in mind that the operating system will remove the saved state when the app is being force-closed by the user, in order to avoid getting stuck in a broken state in case something goes wrong in the state preservation and restoration.<\/p>\n<p>Also, don\u2019t store any model data (i.e. data that should have been saved to UserDefaults or Core Data) to the state, even though it might seem convenient to do so. State data will be removed when the user force quits your app, and you certainly don\u2019t want to lose model data this way.<\/p>\n<p>To test whether state preservation and restoration are working well, follow the steps below:<\/p>\n<ol>\n<li>Build and launch an app using Xcode.<\/li>\n<li>Navigate to the screen with state preservation and restoration that you want to test.<\/li>\n<li>Return to the home screen (by swiping up or double-clicking home button, or pressing <kbd>Shift ?<\/kbd> + <kbd>Cmd ?<\/kbd> + <kbd>H<\/kbd> in the simulator) to send the app to the background.<\/li>\n<li>Stop the app in Xcode by pressing the ? button.<\/li>\n<li>Launch the app again and check whether the state has been restored successfully.<\/li>\n<\/ol>\n<p>Because this section only covers the basics of state preservation and restoration, I recommend the following articles by Apple Inc. for more in-depth knowledge of state restoration:<\/p>\n<ol>\n<li><a href=\"https:\/\/developer.apple.com\/library\/archive\/featuredarticles\/ViewControllerPGforiPhoneOS\/PreservingandRestoringState.html\">Preserving And Restoring State<\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/view_controllers\/preserving_your_app_s_ui_across_launches\/about_the_ui_preservation_process\">UI Preservation Process<\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/view_controllers\/preserving_your_app_s_ui_across_launches\/about_the_ui_restoration_process\">UI Restoration Process<\/a><\/li>\n<\/ol>\n<div><\/div>\n<h3>4. Reduce Usage Of Non-Opaque Views As Much As Possible<\/h3>\n<p>An opaque view is a view that has no transparency, meaning that any UI element placed behind it is not visible at all. We can set a view to be opaque in the Interface Builder:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5af9b5bc-8786-41d9-88ab-2342f69c2b88\/ios-performance-tricks-6-opaque.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-6.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0402cef9-9dc9-4d61-b394-21de713e039b\/ios-performance-tricks-6.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0402cef9-9dc9-4d61-b394-21de713e039b\/ios-performance-tricks-6.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0402cef9-9dc9-4d61-b394-21de713e039b\/ios-performance-tricks-6.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/0402cef9-9dc9-4d61-b394-21de713e039b\/ios-performance-tricks-6.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-6.png?w=900\" sizes=\"100vw\" alt=\"This will inform the drawing system to skip drawing whatever is behind this view\"><\/a><figcaption>\n\t\t\tSet UIView to opaque in storyboard (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/5af9b5bc-8786-41d9-88ab-2342f69c2b88\/ios-performance-tricks-6-opaque.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>Or we can do it programmatically with the <code>isOpaque<\/code> property of UIView:<\/p>\n<pre><code>view.isOpaque = true\n<\/code><\/pre>\n<p>Setting a view to opaque will make the drawing system optimize some drawing performance while rendering the screen.<\/p>\n<p>If a view has transparency (i.e. alpha is below 1.0), then iOS will have to do extra work to calculate what should be displayed by blending different layers of views in the view hierarchy. On the other hand, if a view is set to opaque, then the drawing system will just put this view in front and avoid the extra work of blending the multiple view layers behind it.<\/p>\n<p>You can check which layers are being blended (non-opaque) in the iOS Simulator by checking <em>Debug<\/em> ? <em>Color Blended Layers<\/em>.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/d7c3eeb5-0d64-4b38-9f01-da23dd7d244e\/ios-performance-tricks-7-colorblendedlayers.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-7.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8b312287-e25e-4f1e-ad67-aea5aa91f2f3\/ios-performance-tricks-7.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8b312287-e25e-4f1e-ad67-aea5aa91f2f3\/ios-performance-tricks-7.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8b312287-e25e-4f1e-ad67-aea5aa91f2f3\/ios-performance-tricks-7.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8b312287-e25e-4f1e-ad67-aea5aa91f2f3\/ios-performance-tricks-7.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-7.png?w=900\" sizes=\"100vw\" alt=\"Green is non-color blended, red is blended layer\"><\/a><figcaption>\n\t\t\tShow color blended layers in Simulator<br \/>\n\t\t<\/figcaption><\/figure>\n<p>After checking the <em>Color Blended Layers<\/em> option, you can see that some views are red and some are green. Red indicates that the view is not opaque and that its output display is a result of layers blended behind it. Green indicates that the view is opaque and no blending has been done.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-9-greenish.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-9-greenish.png?w=900\" sizes=\"100vw\" alt=\"With an opaque color background, the layer doesn\u2019t need to blend with another layer\"><\/a><figcaption>\n\t\t\tAssign non-transparent background color to UILabel whenever possible to reduce color blended layers. (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/7dfe406f-434b-4358-8458-7408ba61bcc4\/ios-performance-tricks-9-greenish.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>The labels shown above (\u201cView Friends\u201d, etc.) are highlighted in red because when a label is dragged to the storyboard, its background color is set to transparent by default. When the drawing system is compositing the display near the label area, it will ask for the layer behind the label and do some calculation.<\/p>\n<p>One way you can optimize app performance is to reduce how many views are highlighted with red as much as possible.<\/p>\n<p>By changing <code>label.backgroundColor = UIColor.clear<\/code> to <code>label.backgroundColor = UIColor.white<\/code>, we can reduce layer blending between the label and the view layer behind it.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-8-redgreen.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-8-redgreen.png?w=900\" sizes=\"100vw\" alt=\"Using a transparent background color will cause layer blending\"><\/a><figcaption>\n\t\t\tMany labels are highlighted in red because their background color is transparent, causing iOS to calculate the background color by blending the view behind it. (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/56fc5367-3cca-49f1-a5bd-a5fd15eb1cc0\/ios-performance-tricks-8-redgreen.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>You might have noticed that, even if you have set a UIImageView to opaque and assigned a background color to it, the simulator will still show red in the image view. This is probably because the image you used for the image view has an alpha channel.<\/p>\n<p>To remove the alpha channel for an image, you can use the Preview app to make a duplicate of the image (<kbd>Shift ?<\/kbd> + <kbd>Cmd ?<\/kbd> + <kbd>S<\/kbd>), and uncheck the \u201cAlpha\u201d checkbox when saving.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-10-uncheck.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-10-uncheck.png?w=900\" sizes=\"100vw\" alt=\"Uncheck the \u2018Alpha\u2019 checkbox when saving an image to discard the alpha channel.\"><\/a><figcaption>\n\t\t\tUncheck the \u2018Alpha\u2019 checkbox when saving an image to discard the alpha channel. (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/13b72d22-093d-4957-b297-25c9b950ad4c\/ios-performance-tricks-10-uncheck.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<h3>5. Pass Heavy Processing Functions To Background Threads (GCD)<\/h3>\n<p>Because UIKit only works on the main thread, performing heavy processing on the main thread will slow down the UI. The main thread is used by UIKit not only to handle and respond to user input, and also to draw the screen.<\/p>\n<p>The key to making an app responsive is to move as many heavy processing tasks to background threads as possible. Avoid doing complex calculation, networking, and heavy IO operation (e.g. reading and writing to disk) on the main thread.<\/p>\n<p>You might have once used an app that suddenly became unresponsive to your touch input, and it feels like the app has hung. This is most probably caused by the app running heavy computation tasks on the main thread.<\/p>\n<p>The main thread usually alternates between UIKit tasks (such as handling user input) and some light tasks in small intervals. If a heavy task is running on main thread, then UIKit will need to wait until the heavy task has finished before being able to handle touch input.<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-11-mainthread.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-11-mainthread.png?w=900\" sizes=\"100vw\" alt=\"Avoid running performance-intensive or time-consuming task on the main thread\"><\/a><figcaption>\n\t\t\tHere is how the main thread handles UI tasks and why it causes the UI to hang when heavy tasks are performed. (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8f319bf3-4849-4e94-9c1b-6666415f4f98\/ios-performance-tricks-11-mainthread.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>By default, the code inside view controller lifecycle methods (such as viewDidLoad) and IBOutlet functions are executed on the main thread. To move heavy processing tasks to a background thread, we can use the <a href=\"https:\/\/apple.github.io\/swift-corelibs-libdispatch\/\">Grand Central Dispatch<\/a> queues provided by Apple.<\/p>\n<p>Here\u2019s the template for switching queues :<\/p>\n<pre><code>\/\/ Switch to background thread to perform heavy task.\nDispatchQueue.global(qos: .default).async {\n   \/\/ Perform heavy task here.\n \n   \/\/ Switch back to main thread to perform UI-related task.\n   DispatchQueue.main.async {\n       \/\/ Update UI.\n   }\n}\n<\/code><\/pre>\n<p>The <code>qos<\/code> stands for \u201cquality of service\u201d. Different quality-of-service values indicate different priorities for the specified tasks. The operating system will allocate more CPU time and CPU power I\/O throughput for tasks allocated in queues with higher QoS values, meaning that a task will finish faster in a queue with higher QoS values. A higher QoS value will also consume more energy due to it using more resources.<\/p>\n<p>Here is the list of QoS values from highest to lowest priority:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png?ssl=1\"><br \/>\n\t\t<img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"http:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-12-qos.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-12-qos.png?w=900\" sizes=\"100vw\" alt=\"Quality-of-service values of queue sorted by performance and energy efficiency\"><\/a><figcaption>\n\t\t\tQuality-of-service values of queue sorted by performance and energy efficiency (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/bbfaec6b-7e95-4d5e-a1d6-d5c96944d363\/ios-performance-tricks-12-qos.png\">Large preview<\/a>)<br \/>\n\t\t<\/figcaption><\/figure>\n<p>Apple has provided <a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/Performance\/Conceptual\/EnergyGuide-iOS\/PrioritizeWorkWithQoS.html#\/\/apple_ref\/doc\/uid\/TP40015243-CH39-SW1\">a handy table<\/a> with examples of which QoS values to use for different tasks.<\/p>\n<p>One thing to keep in mind is that all UIKit code should always be executed on the main thread. Modifying UIKit objects (such as <code>UILabel<\/code> and <code>UIImageView<\/code>) on the background thread could have an unintended consequence, like the UI not actually updating, a crash occurring, and so on.<\/p>\n<p>From Apple\u2019s <a href=\"https:\/\/developer.apple.com\/documentation\/code_diagnostics\/main_thread_checker\">article<\/a>:<\/p>\n<blockquote><p>\u201cUpdating UI on a thread other than the main thread is a common mistake that can result in missed UI updates, visual defects, data corruptions, and crashes.\u201d<\/p><\/blockquote>\n<p>I recommend watching <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2012\/211\/\">Apple\u2019s WWDC 2012 video on UI concurrency<\/a> to better understand how to build a responsive app.<\/p>\n<h4>Notes<\/h4>\n<p>The trade-off of performance optimization is that you have to write more code or configure additional settings on top of the app\u2019s functionality. This might make your app delivered later than expected, and you will have more code to maintain in the future, and more code means potentially more bugs.<\/p>\n<p>Before spending time on optimizing your app, ask yourself whether the app is already smooth or whether it has some unresponsive part that really needs to be optimized. Spending a lot of time optimizing an already smooth app to shave off 0.01 seconds might not be worth it, as the time could be better spent developing better features or other priorities.<\/p>\n<h4>Further Resources<\/h4>\n<ul>\n<li>\u201c<a href=\"https:\/\/www.youtube.com\/watch?v=k81HRmMZLXc&#038;t=653s\">A Suite of Delicious iOS Eye Candy<\/a>,\u201d Tim Oliver, Tokyo iOS Meetup 2018 (Video)<\/li>\n<li>\u201c<a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2012\/211\/\">Building Concurrent User Interfaces on iOS<\/a>,\u201d Andy Matuschak, WWDC 2012 (Video)<\/li>\n<li>\u201c<a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/view_controllers\/preserving_your_app_s_ui_across_launches\">Preserving Your App\u2019s UI Across Launches<\/a>,\u201d Apple<\/li>\n<li>\u201c<a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/General\/Conceptual\/ConcurrencyProgrammingGuide\/OperationQueues\/OperationQueues.html\">Concurrency Programming Guide: Dispatch Queues<\/a>,\u201d Documentation Archive, Apple<\/li>\n<li>\u201c<a href=\"https:\/\/developer.apple.com\/documentation\/code_diagnostics\/main_thread_checker\">Main Thread Checker<\/a>,\u201d Apple<\/li>\n<\/ul>\n<div>\n  <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/logo-red-2.png?w=900\" alt=\"Smashing Editorial\"><span>(jd, ra, il)<\/span>\n<\/div>\n<\/article>\n<p class=\"wpematico_credit\"><small>Powered by <a href=\"http:\/\/www.wpematico.com\" target=\"_blank\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>iOS Performance Tricks To Make Your App Feel More Performant iOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00 Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this&#8230;<a class=\"moretag\" href=\"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/\"> Read the full article&#8230;<\/a><\/p>\n","protected":false},"author":4,"featured_media":59900,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[371],"tags":[],"class_list":["post-59899","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-user-experience"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Guest Contribution\"\/>\n\t<meta name=\"keywords\" content=\"user experience\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Design for Immersive Technologies | User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies\" \/>\n\t\t<meta property=\"og:description\" content=\"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-02-06T11:20:33+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-02-06T11:20:33+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies\" \/>\n\t\t<meta name=\"twitter:description\" content=\"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#article\",\"name\":\"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies\",\"headline\":\"iOS Performance Tricks To Make Your App Feel More Performant\",\"author\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/www.taterboy.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/02\\\/ios-performance-tricks-1-dequeue.png?fit=400%2C284&ssl=1\",\"width\":400,\"height\":284},\"datePublished\":\"2019-02-06T04:20:33-07:00\",\"dateModified\":\"2019-02-06T04:20:33-07:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#webpage\"},\"articleSection\":\"User Experience\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.taterboy.com\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"name\":\"User Experience\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"position\":2,\"name\":\"User Experience\",\"item\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#listItem\",\"name\":\"iOS Performance Tricks To Make Your App Feel More Performant\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#listItem\",\"position\":3,\"name\":\"iOS Performance Tricks To Make Your App Feel More Performant\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"name\":\"User Experience\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\",\"name\":\"Design for Immersive Technologies\",\"description\":\"User Experience for Games, Virtual Reality (VR) and Augmented\\\/Mixed Reality (AR\\\/MR)\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/\",\"name\":\"Guest Contribution\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d2aad73eb0f48c67b141e9fc978a0e498969791ed623346e361d02d19775b0bb?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Guest Contribution\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#webpage\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/\",\"name\":\"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies\",\"description\":\"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/www.taterboy.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/02\\\/ios-performance-tricks-1-dequeue.png?fit=400%2C284&ssl=1\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#mainImage\",\"width\":400,\"height\":284},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/02\\\/ios-performance-tricks-to-make-your-app-feel-more-performant\\\/#mainImage\"},\"datePublished\":\"2019-02-06T04:20:33-07:00\",\"dateModified\":\"2019-02-06T04:20:33-07:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/\",\"name\":\"Design for Immersive Technologies\",\"description\":\"User Experience for Games, Virtual Reality (VR) and Augmented\\\/Mixed Reality (AR\\\/MR)\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies","description":"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we","canonical_url":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/","robots":"max-image-preview:large","keywords":"user experience","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#article","name":"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies","headline":"iOS Performance Tricks To Make Your App Feel More Performant","author":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"publisher":{"@id":"https:\/\/www.taterboy.com\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-1-dequeue.png?fit=400%2C284&ssl=1","width":400,"height":284},"datePublished":"2019-02-06T04:20:33-07:00","dateModified":"2019-02-06T04:20:33-07:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#webpage"},"isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#webpage"},"articleSection":"User Experience"},{"@type":"BreadcrumbList","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog#listItem","position":1,"name":"Home","item":"https:\/\/www.taterboy.com\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","name":"User Experience"}},{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","position":2,"name":"User Experience","item":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#listItem","name":"iOS Performance Tricks To Make Your App Feel More Performant"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#listItem","position":3,"name":"iOS Performance Tricks To Make Your App Feel More Performant","previousItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","name":"User Experience"}}]},{"@type":"Organization","@id":"https:\/\/www.taterboy.com\/blog\/#organization","name":"Design for Immersive Technologies","description":"User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","url":"https:\/\/www.taterboy.com\/blog\/"},{"@type":"Person","@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author","url":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/","name":"Guest Contribution","image":{"@type":"ImageObject","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/d2aad73eb0f48c67b141e9fc978a0e498969791ed623346e361d02d19775b0bb?s=96&d=mm&r=g","width":96,"height":96,"caption":"Guest Contribution"}},{"@type":"WebPage","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#webpage","url":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/","name":"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies","description":"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#breadcrumblist"},"author":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"creator":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-1-dequeue.png?fit=400%2C284&ssl=1","@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#mainImage","width":400,"height":284},"primaryImageOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/#mainImage"},"datePublished":"2019-02-06T04:20:33-07:00","dateModified":"2019-02-06T04:20:33-07:00"},{"@type":"WebSite","@id":"https:\/\/www.taterboy.com\/blog\/#website","url":"https:\/\/www.taterboy.com\/blog\/","name":"Design for Immersive Technologies","description":"User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","inLanguage":"en-US","publisher":{"@id":"https:\/\/www.taterboy.com\/blog\/#organization"}}]},"og:locale":"en_US","og:site_name":"Design for Immersive Technologies | User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","og:type":"article","og:title":"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies","og:description":"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we","og:url":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/","article:published_time":"2019-02-06T11:20:33+00:00","article:modified_time":"2019-02-06T11:20:33+00:00","twitter:card":"summary","twitter:title":"iOS Performance Tricks To Make Your App Feel More Performant | Design for Immersive Technologies","twitter:description":"iOS Performance Tricks To Make Your App Feel More PerformantiOS Performance Tricks To Make Your App Feel More Performant Axel Kee 2019-02-05T13:00:00+01:002019-02-06T11:12:17+00:00Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we"},"aioseo_meta_data":{"post_id":"59899","title":null,"description":null,"keywords":null,"keyphrases":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_custom_image_width":null,"og_custom_image_height":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"created":"2021-02-07 22:38:29","updated":"2026-09-01 03:52:59","focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"primary_term":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"twitter_image_url":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"limit_modified_date":false,"ai":null,"breadcrumb_settings":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.taterboy.com\/blog\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/\" title=\"User Experience\">User Experience<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tiOS Performance Tricks To Make Your App Feel More Performant\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.taterboy.com\/blog"},{"label":"User Experience","link":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/"},{"label":"iOS Performance Tricks To Make Your App Feel More Performant","link":"https:\/\/www.taterboy.com\/blog\/2019\/02\/ios-performance-tricks-to-make-your-app-feel-more-performant\/"}],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8wzr5-fA7","jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/02\/ios-performance-tricks-1-dequeue.png?fit=400%2C284&ssl=1","_links":{"self":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/59899","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/comments?post=59899"}],"version-history":[{"count":0,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/59899\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media\/59900"}],"wp:attachment":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media?parent=59899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/categories?post=59899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/tags?post=59899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}