IOS25 performance optimization, memory optimization, and ios25 Performance Optimization
1. Use ARC to manage memory
ARC (Automatic ReferenceCounting, Automatic reference counting) and iOS5 are released together to avoid Memory leakage, which is often caused by memory loss. It automatically manages retain and release processes for you, so you don't have to intervene manually. Forgetting the release at the end of the code snippet is as easy as remembering to eat. And ARC will automatically do the work for you at the underlying layer. In addition to helping you avoid memory leaks, ARC can also help you improve performance and ensure that the memory of unwanted objects is released.
2. Use reuseIdentifier in the correct place
A common error in development is that UITableViewCells, UICollectionViewCells, or even UITableViewHeaderFooterViews are not set with the correct reuseIdentifier.
To optimize the performance, when table view uses 'tableview: cellForRowAtIndexPath: 'To allocate cells to rows, its data should be reused from UITableViewCell. A table view maintains a reusable UITableViewCell object for data in a queue.
If you do not use reuseIdentifier, you have to set up a new cell for each row of table view. This has a considerable impact on the performance, especially reducing the rolling experience of the app.
From iOS6, you should also use reuseIdentifiers In header and footer views in addition to UICollectionView cells and supplemental views.
To use reuseIdentifiers, add this method to the data source object when adding a new cell to a table view:
StaticNSString * CellIdentifier = @ "Cell ";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier forIndexPath: indexPath];
This method removes existing cells from the queue, or creates new cells using previously registered nib or class when necessary. If there is no reusable cell and you have not registered a class or nib, this method returns nil.
3. Set views as transparent as possible
If you have transparent Views, you should set their opaque attribute to YES.
This causes the system to render these views in an optimal way. This simple attribute can be set in IB or code.
Apple's documentation describes how to set transparent attributes for images:
(Opaque) This attribute provides the rendering system with a prompt on how to handle this view. If set to YES, the rendering system considers this view to be completely opaque, which enables the rendering system to optimize some rendering processes and improve performance. If it is set to NO, the rendering system normally forms this View with other content. The default value is YES.
Setting this attribute in relatively static images does not have much impact. However, when this view is embedded in a scroll view or a part of a complex animation, if this attribute is not set, the app performance will be greatly affected.
You can use the Debug \ Color Blended Layers option in the simulator to find which views are not set to opaque. The goal is to set all opaque!
4. Avoid too large XIB
The Storyboards (mirror) added to iOS5 is rapidly replacing XIB. However, XIB is still useful in some scenarios. For example, if your app needs to adapt to a device before iOS5, or you have a custom reusable view, you will inevitably need to use them.
If you have to perform XIB, make them as simple as possible. Try to configure a separate XIB for each Controller and distribute the View hierarchy of A view Controller to a separate XIB.
Note that when you load an XIB file, all the content is stored in the memory, including any image. If there is a view that will not be used immediately, you are wasting valuable memory resources. Storyboards is another code. storyboard instantiates a view controller only when needed.
In the case of XIB, all images are chache. If you are developing OS X, the sound file is also used. Apple's description in related documents is:
When you load a nib that references an image or sound resource, the nib Load Code will write the image and sound file into the memory. In OS X, image and sound resources are cached in the named cache for future use. In iOS, only image resources are saved in named caches. Depending on your platform, use NSImage or the 'imagenamed: 'method of UIImage to obtain image resources.
5. Do not block the main thread
Never take too much of the main thread. Because UIKit does all the work on the main thread, rendering, management touch response, and response input all need to be done on it.
The risk of using the main thread is that if your code blocks the main thread, your app will lose response.
In most cases, your app is performing I/O operations involving reading and writing external resources, such as storage or network operations.
You can use 'nsurlconnection' to perform Asynchronous Network Operations:
+ (Void) sendAsynchronousRequest :( NSURLRequest *) request queue :( NSOperationQueue *) queue completionHandler :( void (^) (NSURLResponse *, NSData *, NSError *) handler
Or use a framework like AFNetworking to perform these operations asynchronously.
If you need to perform other types of operations that require huge resources (such as time-sensitive computing or storage read/write), use Grand Central Dispatch, or NSOperation and NSOperationQueues.
The following code uses the GCD Template
Dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
// Switch to a background thread and perform your expensive operation
Dispatch_async (dispatch_get_main_queue (), ^ {
// Switch back to the main thread to update your UI
});
});
Is there a nested 'dispatch _ async 'in the code? This is because any UIKit-related code needs to be performed on the main thread.
6. Adjust the Image size in Image Views
If you want to display an image from bundle in 'uiimageview', make sure that the image size is the same as that of UIImageView. Scaling images at run time is resource-consuming, especially when 'uiimageview' is nested in 'uiscrollview.
If the image is loaded from the remote service, you cannot control the image size. For example, if you want to adjust the image size before downloading, you can use background thread to scale the image once after the download is complete, then use the scaled image in UIImageView.
7. Select the correct Collection
Choosing the most appropriate class or object for a business scenario is the basis for writing highly energy efficient code. This statement is especially true when handling collections.
Summary of some common collections:
· Arrays: a set of ordered values. Using index to lookup is very fast. Using value lookup is very slow, and inserting/deleting is very slow.
· Dictionaries: stores key-value pairs. It is faster to search with a key.
· Sets: unordered values. Search quickly with values and insert/delete quickly.
8. Open gzip Compression
A large number of apps depend on remote resources and third-party APIs. You may develop an app that needs to download XML, JSON, HTML, or other formats from the remote end.
The problem is that we target mobile devices, so you can't count on the good network conditions. A user is still on the edge network and may switch to 3 GB in the next minute. No matter what the scenario is, you certainly don't want your users to wait too long.
One way to reduce the document size is to open gzip on the server and your app. This is more effective for text data with a higher compression ratio.
The good news is that iOS already supports gzip compression by default in NSURLConnection, and AFNetworking is also based on its framework. Cloud service providers such as Google App Engine have also supported compressed output.
9. lazy load Views
More views mean more rendering, that is, more CPU and memory consumption. This is especially true for apps nested with many views in UIScrollView.
Here, we use the technique of imitating the operations of 'uitableview' and 'uicollectionview': do not create all subviews at a time, but create them only when necessary. When they fulfill their mission, put them in a reusable queue.
In this way, you only need to create your views when scrolling occurs to avoid uneconomical memory allocation.
The Energy Efficiency problem of creating views also applies to other aspects of your app. Imagine a scenario where a user needs to display a view when clicking a button. There are two implementation methods:
1. Create and hide the view. When the screen is loaded, it is displayed as needed;
2. It is created and displayed only when necessary.
Each solution has its own advantages and disadvantages. If you use the first scheme, you need to create a view from the beginning and keep it until it is no longer used, which will consume more memory. However, this will make your app operations more sensitive, because when you click a button, it only needs to change the visibility of this view.
The second solution is the opposite-it consumes less memory, but it will be slightly worse than the first one when you click the button.
10. Cache, Cache, or Cache!
An excellent principle is that what the cache requires is something that is unlikely to change but needs to be read frequently.
What Can We cache? Some options are remote server response, images, and even calculation results, such as the Row Height of UITableView.
By default, NSURLConnection caches Resources in the memory or storage based on the HTTP Headers it loads. You can even manually create an NSURLRequest to load only the cached value.
The following is an available code segment. You can use it to create an NSURLRequest for a basically unchanged image and cache it:
+ (NSMutableURLRequest *) imageRequestWithURL :( NSURL *) url {
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL: url];
Request. cachePolicy = NSURLRequestReturnCacheDataElseLoad; // this will make sure the request always returns the cached image
Request. HTTPShouldHandleCookies = NO;
Request. HTTPShouldUsePipelining = YES;
[Request addValue: @ "image/*" forHTTPHeaderField: @ "Accept"];
Return request;
}
Note that you can obtain a URL request through NSURLConnection, and AFNetworking is the same. In this way, you do not have to change all the networking code to use this tip.
If you need to cache other things that are not HTTP Request, you can use NSCache.
NSCache is similar to NSDictionary. The difference is that when the system recycles the memory, it will automatically delete its content.
11. Weigh the Rendering Method
There are many ways to make beautiful buttons in iOS. You can use the whole picture, adjustable size picture, uozhe can use CALayer, CoreGraphics or even OpenGL to draw them.
Of course, each different solution has different complexity and corresponding performance.
Simply put, it is faster to use a previously rendered image, because iOS removes the need to create an image, draw it, and display it on the screen. The problem is that you need to put all the images you need into the app bundle, which increases the volume-this is where it is better to use a variable size image: you can save unnecessary space and do not need to create different diagrams for different elements (such as buttons.
However, using images also means you lose the flexibility to adjust images using code. You need to redo them over and over again, which is a waste of time, and if you want to make an animation effect, although each image is only a little changed in details, you need a lot of images to increase the bundle size.
In general, you need to weigh the advantages and disadvantages to determine whether to maintain proper performance or bundle size.
12. Handle memory warnings
Once the system memory is too low, iOS notifies all running apps. In the official document, it is described as follows:
If your app receives a memory warning, it needs to release as much memory as possible. The best way is to remove strong references for cache, image objects, and other objects that can be recreated.
Fortunately, UIKit provides several methods to collect low-memory Warnings:
· Use the 'applicationdidreceivemorywarning: 'method in app delegate
· Overwrite 'didreceiveemorywarning' In the subclass of your custom UIViewController'
· Register and receive notifications from UIApplicationDidReceiveMemoryWarningNotification
Once you receive such notifications, you need to release any unnecessary memory usage.
For example, the default behavior of UIViewController is to remove some invisible views. Some of its subclasses can supplement this method to delete some additional data structures. An app with image cache can remove images that are not displayed on the screen.
In this way, it is necessary to process the memory alarm. If you do not pay attention to it, your app may be killed by the system.
However, you must ensure that the selected object can be recreated to release the memory. Be sure to use the memory in the simulator for testing during development.
13. Reuse large-sale objects
Some objects Initialization is slow, such as NSDateFormatter and NSCalendar. However, you need to use them, such as parsing data from JSON or XML.
To avoid the bottleneck of using this object, you need to reuse them. You can add attributes to your class or create static variables.
Note that if you select the second method, the object will always exist in the memory when your app is running, similar to singleton.
The following code uses a property to delay loading a date formatter. During the first call, it creates a new instance. In future calls, it returns the created instance:
// In your. h or inside a class extension
@ Property (nonatomic, strong) NSDateFormatter * formatter;
// Inside the implementation (. m)
// When you need, just use self. formatter
-(NSDateFormatter *) formatter {
If (! _ Formatter ){
_ Formatter = [[NSDateFormatter alloc] init];
_ Formatter. dateFormat = @ "eee mmm dd HH: mm: ss Z yyyy"; // twitter date format
}
Return_formatter;
}
Note that setting an NSDateFormatter is almost as slow as creating a new one! Therefore, if your app needs to process the date format frequently, you will get a significant performance improvement from this method.
14. Use Sprite Sheets
Sprite sheet can speed up rendering and even save memory than standard screen rendering methods.
15. Avoid repeated Data Processing
Many applications need to load data in JSON or XML format from the server. It is important to use the same data structure on the server and client. It is costly to operate data in the memory so that they meet your data structure.
For example, if you need data to display a table view, you 'd better retrieve the data in the array structure from the server directly to avoid extra changes in the intermediate data structure.
Similarly, if you want to retrieve data from a specific key, you can use the dictionary of the key-value pair.
16. Select the correct data format
There are many solutions to transmit data between apps and network services. The most common solutions are JSON and XML. You need to select the most suitable one for your app.
JSON Parsing is faster than XML, and JSON is usually smaller for transmission. Since iOS5, the official built-in JSON deserialization is more convenient to use.
However, XML also has the advantages of XML. For example, using SAX to parse XML is like parsing a local file. You do not need to wait until the entire file is downloaded just like parsing json. When you process a large amount of data, it will greatly reduce memory consumption and increase performance.
17. Set the background image correctly.
Putting background images in a View is like many other iOS programming methods:
Use colorWithPatternImage of UIColor to set the background color;
Add a UIImageView to the view as a sub-View.
If you use a full-frame background image, you must use UIImageView because the colorWithPatternImage of UIColor is used to create a small duplicate image as the background. In this case, using UIImageView can save a lot of memory:
// You cocould also achieve the same result in Interface Builder
UIImageView * backgroundView = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @ "background"];
[Self. view addSubview: backgroundView];
If you use a small image tile to create a background, you need to use the colorWithPatternImage of UIColor to make rendering faster and it will not spend much memory:
Self. view. backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed: @ "background"];
18. Reduce the use of Web features
UIWebView is very useful. It is very easy to use to display webpage content or create animations that are hard to achieve by using UIKit.
However, you may notice that the UIWebView is not as fast as the Safari driver. This is due to the limitations of the Nitro Engine of Webkit featuring JIT compilation.
To achieve higher performance, you need to adjust your HTML. The first thing to do is remove unnecessary javascript as much as possible to avoid using too large frameworks. It is better to use only native js.
In addition, load javascript that does not affect page expression, such as user behavior statistics script, asynchronously as much as possible.
Finally, always pay attention to the image you are using to ensure that the image size meets your needs. Use Sprite sheet to increase loading speed and save memory.
19. Set Shadow Path
How can I add a shadow to a View or layer? The QuartzCore framework is the choice of many developers:
# Import
// Somewhere later...
UIView * view = [[UIView alloc] init];
// Setup the shadow...
View. layer. shadowOffset = CGSizeMake (-1.0f, 1.0f );
View. layer. shadowRadius = 5.0f;
View. layer. shadowOpacity = 0.6;
It looks simple, right. However, bad messages are caused by this method... Core Animation has to draw your graphics in the background and add Shadows before rendering. This overhead is very high.
This problem is avoided by using shadowPath:
View. layer. shadowPath = [[UIBezierPath bezierPathWithRect: view. bounds] CGPath];
If shadow path is used, iOS does not have to calculate how to render it every time. It uses a pre-calculated path. However, if you calculate the path by yourself, it may be difficult in some views. You need to update the shadow path whenever the frame of the View changes.
20. Optimize Table View
Table view must have good rolling performance. Otherwise, you will find animation flaws During the rolling process.
To ensure smooth table view scrolling, you have taken the following measures:
· Correct use of 'reuseidentifier' to reuse cells
· Try to make all the view opaque, including the cell itself
· Avoid gradient, image scaling, and background selection
· Cache Row Height
· If the actual content in the cell comes from the web, use asynchronous loading to cache the request results
· Use 'shadowpath' to draw shadows
· Reduce the number of subviews
· Try not to use 'cellforrowatindexpath: '. If you need to use it, use it only once and then cache the result.
· Use the correct data structure to store data
· Use 'rowheight', 'sectionfooterheight', and 'sectionheaderheight' to set a fixed height. Do not request delegate.
21. Select the correct data storage option
What do you do when you store large volumes of data?
You have many options, such:
· Use 'nsuerdefaults'
· Use XML, JSON, or plist
· Use NSCoding for archiving
· Use a local SQL database similar to SQLite
· Use Core Data
What is the problem with NSUserDefaults? Although it is nice and convenient, it only applies to small data, such as some simple boolean setting options. If it is bigger, you need to consider other methods.
What about structured files like XML? In general, you need to read the entire file to the memory for parsing, which is very economic. Using SAX is a very troublesome task.
NSCoding? Unfortunately, it also needs to read and write files, so there are also the above problems.
In this application scenario, it is better to use SQLite or Core Data. With these technologies, you can use specific query statements to load only the objects you need.
In terms of performance, SQLite and Core Data are very similar. Their difference lies in the specific use method. Core Data represents the graph model of an object, but SQLite is a DBMS. Apple generally recommends using Core Data, but if you have reason not to use it, use a more underlying SQLite.
If you use SQLite, you can use the FMDB (https://GitHub.com/ccgus/fmdb) library to simplify SQLite operations, so you don't have to spend a lot of time learning about the c api of SQLite.
23. Use Autorelease Pool
The 'utoreleasepool 'is responsible for releasing autoreleased objects in the block. Generally, it is automatically called by UIKit. But in some cases, you also need to manually create it.
If you create many temporary objects, you will find that the memory is decreasing until these objects are release. This is because memory is released only when the UIKit uses autorelease pool. The good news is that you can create a temporary object in your own @ autoreleasepool to avoid this behavior:
NSArray * urls = <# An array of file URLs #>;
For (NSURL * url in urls ){
@ Autoreleasepool {
NSError * error;
NSString * fileContents = [NSString stringWithContentsOfURL: url encoding: NSUTF8StringEncoding error: & error];
/* Process the string, creating and autoreleasing more objects .*/
}
}
This code releases all autorelease objects after each traversal.
24. Select whether to cache Images
There are two common methods to load images from bundle: 'imagenamed' and 'imagewithcontentsoffile. The first method is more common.
Since there are two similar methods to achieve the same purpose, what is the difference between them?
The advantage of 'imagenamed' is that the image is cached during loading. In the 'imagenamed' document, this method searches for and returns an image object in the system cache with a specified name if it exists. If no image is found in the cache, this method loads the image from the specified file, caches the image, and returns the object.
Conversely, 'imagewithcontentsoffile 'Only loads images.
The following code illustrates the usage of these two methods:
UIImage * img = [UIImage imageNamed: @ "myImage"]; // caching
// Or
UIImage * img = [UIImage imageWithContentsOfFile: @ "myImage"]; // no caching
So how should we choose?
If you want to load a large image and use it all at once, there is no need to cache the image. You can use 'imagewithcontentsoffile 'to cache it without wasting memory.
However, 'imagenamed' is a much better choice when images are repeatedly reused.
25. Avoid Date Format Conversion
If you want to use 'nsdateformatter 'to process many date formats, be careful when waiting. As mentioned earlier, reusing 'nsdateformatters 'at any time is a good practice.
However, if you need more speed, directly using C is a good solution. Sam Soffes has a good post (http://soff.es/how-to-drastically-improve-your-app-with-an-afternoon-and-instruments) There are some code that can be used to parse the ISO-8601 date string, simple rewriting can be used.
Well, it looks good to use C directly. But do you believe we have a better solution!
If you can control the date format you are processing, try to select a Unix timestamp. You can easily convert from a timestamp to an NSDate:
-(NSDate *) dateFromUnixTimestamp :( NSTimeInterval) timestamp {
Return [NSDate dateWithTimeIntervalSince1970: timestamp];
}
This will be faster than parsing the date string with C! Note that many web APIs return timestamps in microseconds, because this format is more convenient to use in javascript. Remember to use 'datefromunixtimestamp' before dividing by 1000.