iOS Performance Tuning Summary

Source: Internet
Author: User
Tags gcd stack trace uikit

Introduction

Speaking of performance tuning, I wanted to say a lot, but the boring language doesn't express my emphasis on performance tuning, so I'm going to give you an inappropriate example.

曾经有这么一家工厂,他们的产品从原材料到出厂一共需要经过30条产品线。这家公司的老板对底下的员工曾多次强调过质量的重要性,员工们却不以为然,他们觉得自己做的都很不错。有一次,老板去视察,走到了一条产品线上,问起工人,这条产品线的合格率能达到多少,那个工人自豪的说,"98%!"。老板却并没有十分满意,摇着头走开了。那位工人非常的疑惑。这么高的合格率,老板为什么还是不满意呢?于是这位工人就去向领导打听,领导也不知道,于是后来这位工人直接找到了老板家里,向老板请教。老板很是诧异,于是就给这位工人简单科普了一下,一条产品线的合格率是98%,并不代表最后总的合格率是98%。应该是这样计算最后的合格率的:

x=0.98?0.98?0.98 ...= 0.98 =0.545
Therefore, the company's production line is actually only 54.5% pass rate.

This story explains the problem is very simple, we develop the final performance of the app, are composed of every small part of the composition, many of the content is to do multiplication, rather than add and subtract, so want to design their own app to let users use the cool, any small performance problems we can not ignore.

How performance is tuned:
1、通过专门的性能调优工具2、通过优化代码
1. Performance Tuning Tools:

The following is an introduction to the Performance Tuning tool for iOS:

1.1 Static analysis Tools –analyze

When iOS developers build or archive the app, there are a lot of compile warnings that are generated at compile time, and the process of static analysis is similar, under the XCode Product menu, click Analyze Static analysis of the app.

Analyze mainly analyzes the following four types of problems:

1. 逻辑错误:访问空指针或未初始化的变量等;2. 内存管理错误:如内存泄漏等;3. 声明错误:从未使用过的变量;4. Api调用错误:未包含使用的库和框架。
1.2 Memory leak analysis tool –leaks

Click the Xcode Product menu profile to start Instruments, and use leaks to start the dynamic analysis.
Selecting leaks automatically launches the leaks tool and the iOS emulator, and leaks starts recording when it starts, and you can view the memory footprint in leaks as you work with the app running on the emulator.

注:如果你的项目使用了ARC,随着你的操作,不断开启或关闭视图,内存可能持续上升,但这不一定表示存在内存泄漏,ARC释放的时机是不固定的。

The top of the leaks is divided into two columns: allocations and leaks, and the curve on the right represents memory allocation and memory leak curves.

Click on the second column leaks, for memory leak analysis, the lower left corner will appear leaks debugging options:

It is recommended that the snapshot interval interval be set to 10 seconds, and the automatic Snapshotting,leaks will automatically perform a memory capture analysis.

Before and after you suspect a memory leak, you can click Snapshot now to manually capture it.

Here's a view that switches to the calling function in my app to +(UIImage*)getSubImage:(unsigned long)ulUserHeader see a memory leak:

The leaked object table shows the type, number, and memory space of the memory leak.

Clicking on a specific memory leak object in the right detail window will cause the leak to appear where the black avatar represents the most likely location.

Leaks has successfully identified [Cmtool getsubimage:] This function:

memory leak dynamic Analysis Tips

Skilled use of leaks will be more accurate in the memory leak judgment, in the operation that can lead to leakage, more use snapshot now manual capture.

You can set the auto capture interval to 5 seconds if the device performs well at the beginning.

With ARC projects, general memory leaks are caused by malloc, custom structures, and resources, paying more attention to these areas for analysis.

causes of memory leaks after arc is turned on

There is no memory problem with open arc, and Apple has a famous saying: Arc is just for nsobject.

Using the memory allocated by malloc in iOS, ARC is not processed and needs to be handled by itself.

The cgimageref in the example is also a pointer to an image, and arc will not be processed.

1.3 Unreasonable memory analysis tool –allocation

With regard to memory, there may also be an unreasonable use of memory in addition to memory leaks, which can also cause iOS memory warnings.

The irrational use of memory is often more difficult to find than memory leaks, memory leaks can be more aided by tool judgment, and the irrational use of memory requires developers to combine code and architecture for analysis.

Clearly explain the difference between the two:

内存泄漏:是指内存被分配了,但程序中已经没有指向该内存的指针,导致该内存无法被释放,产生内存泄漏。内存不合理运用:苹果官方称这种情况为Abandoned Memory,也就是存在已分配内存的引用,但实际上程序中不会使用,比片等对象加入了缓存,但缓存中的对象一直没有被使用。

The Allocation tool in the Instruments provided by Xcode can be used to help you understand the allocation of memory, and when your app receives a memory warning, it should first use Allocation for memory analysis. Learn which objects are consuming too much memory.

1.4 Kill Zombie Object –zombies

The Zombie object, which is the exc_bad_access error we will encounter, is caused by the memory being released and the object still retaining that bad address.
This error is common in MRC development, and it is also encountered in code that uses C + + under arc.
However, this tool is relatively simple, encountered such errors, open the tool located under the Instruments , directly can help you locate, here will not repeat.

1.5 Performance boost Tool –time profile

The heavy weight of this article!

Since it is performance tuning, how to improve the efficiency of the code is actually the most direct request of our programmers, and this tool can help us to do this thing.

Time Profiler Analysis principle: It tracks the stack information for each thread at regular intervals, calculates how long a method executes and obtains an approximation by statistically comparing the stack state between intervals. It counts the time spent by each method and forms a good helper for directly locating code that needs to be optimized.

Select the Time Profiler tool to start the test, and the simulator and time Profiler recording will be started automatically.

Start with some apps and let time Profiler collect enough data, especially where you think there are performance bottlenecks.

4, 5, 6 labeled Panel is to be concerned about:

4 is the expansion panel, used to track the display stack, 5 is the detailed panel, you can see from here where the CPU is running, and 6 is the options panel, you can set the time Profiler to run parameters.

By manipulating the app, you can see what the most time-consuming actions are in the detail panel, and you can expand the view on a line-by-row basis:

The icon for the black avatar is the cue that time Profiler gives us, where there may be a performance bottleneck where you can gradually expand down to find the root cause.

Time Profiler parameter Settings

Here are a few options that have the following meanings:

    • Separate by thread: each thread should be considered separately. Only in this way can you pull out the heavy threads that consume a lot of CPU
    • Invert call Tree: From the top down the trace stack, which means that the method you see in the table will have been sampled from frame No. 0, which is usually what you want, so you can see the most time-out method in the CPU. That is, funca{funb{func}} Tick the stack with c->b-a to show the deepest C at the outermost level of the call
    • Hide Missing Symbols: If dSYM can't find your app or system frame, you can't see the method name in the table, only 16 binary values are visible, and if this item can hide the symbols, it's easy to simplify the data
    • Hide System Libraries: Check this to show your app's code, which is very useful. Because usually you only care about the time the CPU spends on its own code, not on the system.
    • Show Obj-c only: Show OC code only, if your program is a program like OpenGL, do not tick sideways because he might be C + +
    • Flatten recursion: Recursive function, one entry per stack trace
    • Top Functions: The sum of the time that a function spends directly in the function, and the total time it takes for the function to call the function. So, if function A calls B, then A's time to report a time spent in a plus B takes time, which is really useful because it allows you to pick the maximum number of times each time you go down to the call stack, zeroing in on your most-time-consuming method.

The above parameters are set rationally in practice, and there is not much skill, that is, by hiding and displaying data, we focus more on the data we want to find.

2. Optimized code for Performance tuning:

Here's a look at the aspects of code optimization that you can do directly in development.

2.1 Views set to Opaque (Opaque=yes)

(opaque) This property gives the rendering system a hint on how to handle the view. If set to Yes, the rendering system considers the view to be completely opaque, which allows the rendering system to optimize some rendering processes and improve performance.

If set to no, the rendering system is normally composed of this view with other content. The default value is yes.

Show you a picture, you know, if this property is no, then:

You know, the GPU uses the layer color composition formula to synthesize real color values, which are very performance-intensive in scrollview or animations.

2.2 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, managing touch reactions, responding to input, etc. all need to be done on it.

The risk of using the main thread all the time is that if your code really blocks the main thread, your app will lose its response.

Most of the situations that hinder the main process are that your app is doing some I/O operations that involve reading and writing external resources, such as storage or networking.

It is generally recommended that these operations be executed asynchronously using GCD, and that UI-related operations are invoked on the main thread, such as:

dispatch_async0), ^{    // 切换到全局队列,异步执行耗时操作    dispatch_async(dispatch_get_main_queue(), ^{        // 切换到主线程,更新你的UI。    });});
2.3 Adjust the image size in ImageView (rendering with pictures and animations) in advance

If you want to UIImageView display a picture in, you should make sure that the size of the picture is the same size as the Uiimageview.
Because scaling pictures in the run is a resource-intensive situation, especially if UIImageView nested in UIScrollView .

If the picture is loaded from the remote service and you can't control the size of the image, such as resizing before downloading, you can do it with background thread, and then use the scaled image in Uiimageview.

This analogy is common in the rendering of images and animations.

Refer to the above GCD operation for specific methods.

2.4 Proper use of container properties
    • Arrays: An ordered set of values. Using index to find quickly, using value lookup is slow, insert/delete is slow.
    • Dictionaries: Stores key-value pairs. Use keys to find faster.
    • Sets: An unordered set of values. Use values to find quick, insert/delete soon.
2.5 Large file transfers using gzip

A lot of apps rely on remote resources and third-party APIs, and you might develop an app that needs to download XML, JSON, HTML, or other formats from the far end.

The problem is that we're targeting mobile devices, so you can't count on how good the network is. One user is still on the edge network, and the next minute may switch to 3G. No matter what the scene, you certainly don't want your users to wait too long.

One way to reduce the document is to open gzip on the server and in your app. This will have a more significant effect on the type of data that can have a higher compression rate.

Of course, now that Apple has auto-support, you just need to tell your friends on the server, when transferring large files, remember to use gzip.

2.6 View reuse and lazy loading

More view means more rendering, which is more CPU and memory consumption, especially for apps that have nested a lot of view inside Uiscrollview.

Reuse is UITableView The imitation and UICollectionView manipulation: Do not create all subview at once, but create them when needed, and when they have fulfilled their mission, put them into a reusable queue.
When you need to use view, go to the reusable queue and look for any view that can be reused.
I have used a similar method in my framework to create a picture browser, you can do a little reference. Reuse of view

Lazy loading is not loaded when the program starts, only when the object is used.
This can be used not only in attributes, but also on view, although the implementation is slightly different.
Lazy loading consumes less memory, but there is a slight lag in the view display.

2.7 Cache

An excellent principle is that caching is needed, which is something that is unlikely to change but that needs to be read frequently.

What can we cache? Some of the options are remote server responses, images, and even calculation results, such as UITableView line Heights.

Nsurlconnection default caches the resources in memory or in storage based on the HTTP Headers it loads. You can even manually create a nsurlrequest and then make it load only the cached values.

Here is an available code snippet that you can use to create a nsurlrequest and cache it for a picture that doesn't change a basic one:

+ (NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    request.cachePolicy// this will make sure the request always returns the cached image    request.HTTPShouldHandleCookiesNO;    request.HTTPShouldUsePipeliningYES;    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];    return request;}

Note that you can get a URL request via Nsurlconnection, afnetworking is the same. This way you don't have to change all the networking code to use this tip.

If you want to learn more about HTTP caching, Nsurlcache, nsurlconnection, you can read this article.

If you need to cache other things that are not HTTP request, you can use Nscache.

Nscache and Nsdictionary are similar, the difference is that when the system reclaims memory, it will automatically delete its contents. Mattt Thompson has a great article about it:: http://nshipster.com/nscache/

2.8 Remember to handle memory warnings

Once the system memory is low, iOS notifies all running apps. In the official documentation, this is the description:

如果你的app收到了内存警告,它就需要尽可能释放更多的内存。最佳方式是移除对缓存,图片object和其他一些可以重创建的objects的strong references.

Fortunately, Uikit provides several ways to collect low-memory warnings:

    • Ways to use in app delegate applicationDidReceiveMemoryWarning:
    • Overwrite in your custom Uiviewcontroller subclass (subclass)didReceiveMemoryWarning
    • Register and receive notifications from Uiapplicationdidreceivememorywarningnotification

Once you receive such notifications, you will need to release any unnecessary memory usage.

例如,UIViewController的默认行为是移除一些不可见的view, 它的一些子类则可以补充这个方法,删掉一些额外的数据结构。一个有图片缓存的app可以移除不在屏幕上显示的图片。

This is necessary to handle the memory alert, and if you do not pay attention to it, your app may be killed by the system.

However, when you have to make sure that the object you have chosen can be recreated and created to free up memory. Be sure to test it in development with a memory alert simulation in the simulator.

2.9 Reuse of large overhead objects

The big overhead here refers to some objects that are very slow to initialize , such as NSDateFormatter and Nscalendar. However, you will inevitably need to use them, such as parsing data from JSON or XML.

To avoid using this object's bottlenecks you need to reuse them, either by adding attributes to your class or by creating static variables.

Note that if you choose the second method, the object will persist in memory while your app is running, similar to the Singleton (singleton).

The following code illustrates the use of a property to delay loading a date formatter. On the first call, it creates a new instance, and subsequent calls return the instance that was created:

// in your .h or inside a class extension@property (nonatomicstrong) 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;}

It is also important to note that the speed of setting up a nsdateformatter is almost as slow as creating a new one! So if your app needs to be processed on a regular date format, you'll get a little performance boost from this approach.

2.10 Avoid repetitive processing of data

Many applications require data that is often JSON or XML-formatted to be loaded from the server. It is important to use the same data structure on both the server side and the client. It is expensive to manipulate the data in memory so that they meet your data structure.

For example, if you need data to show a table view, it is best to take the array structure data directly from the server to avoid additional intermediate data structure changes.

Similarly, if you need to fetch data from a specific key, then you use the dictionary of the key-value pair.

2.11 Setting the background image correctly

There are many ways to put a background image in view like many other iOS programs:

    • Use Uicolor's colorwithpatternimage to set the background color;
    • Add a uiimageview as a child view in the view.

If you use full-frame backgrounds, you must use Uiimageview because Uicolor's colorwithpatternimage is used to create small duplicate images as backgrounds. In this case, the use of Uiimageview can save a lot of memory:

// You could also achieve the same result in Interface BuilderUIImageView *backgroundView = [ [UIImageView alloc] initWithImage:[UIImage imageNamed:@"background"]];[self.view addSubview:backgroundView];

If you use a small tiling to create a background, you need to do it with Uicolor's colorwithpatternimage, which will render faster and will not cost much memory:

self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background"]];
2.12 Try Apple's newest Wkwebview to handle the web

UIWebView is very useful, it is simple to use it to display Web content or to create animations that are difficult to uikit.

But you may have noticed that UIWebView is not as fast as driving safari. This is due to the webkit of the Nitro engine which features the JIT compilation.

So if you want higher performance, you need to tweak your HTML. The first thing to do is to remove unnecessary javascript as much as possible and avoid using too large a frame. It's better to use only native JS.

In addition, it is possible to asynchronously load JavaScript such as user behavior statistics script, which does not affect page representations.

Finally, always pay attention to the pictures you use to ensure that the pictures match the size you use. Use sprite sheet to increase loading speed and save memory.

Of course, the above is for you in the case of using UIWebView, you need to minimize the use of the Web features, and Apple recently launched the safari of the underlying framework Wkwebview may help us to avoid a lot of such performance problems.

2.13 Optimizing Your TableView

Table view requires good scrolling performance, otherwise the user will find the artifacts of the animation during scrolling.

To ensure a smooth scrolling of table view, make sure you take the following actions:

    • Use correctly reuseIdentifier to reuse cells
    • Try to make all the view opaque, including the cell itself
    • Avoid gradients, picture scaling, background selection
    • Cache Row Height
    • If the real content within the cell comes from the web, using asynchronous loading, the cache request results
    • Use shadowPath to draw shadows
    • Reduce the number of subviews
    • Try not to apply cellForRowAtIndexPath: , if you need to use it, use it only once and then cache the result
    • Use the correct data structure to store the information
    • Use rowHeight , sectionFooterHeight and sectionHeaderHeight to set a fixed high, do not request delegate
2.14 Choosing the right data storage method

What do you do when you store large chunks of data?

You have many options, such as:

    • UseNSUerDefaults
    • Using XML, JSON, or plist
    • Using Nscoding Archive
    • Using a local SQL database similar to SQLite
    • Using Core Data

What is the problem with Nsuserdefaults? Although it is very nice and convenient, but it only applies to small data, such as some simple Boolean settings options, and then you need to consider other ways

What about this structured file of XML? Overall, you need to read the entire file into memory to parse it, which is very economical. Using sax is another tricky thing to do.

Nscoding? Unfortunately, it also needs to read and write files, so there are the above problems.

In this scenario, it is better to use SQLite or Core data. Using these techniques, you can load only the objects you need with specific query statements.

In terms of performance, SQLite and core data are very similar. Their difference is in the use of specific methods. Core data represents the graph model of an object, but SQLite is a DBMS. Apple generally recommends using core Data, but if you have a reason not to use it, then use the more basic SQLite.

If you use SQLite, you can use Fmdb (Https://github.com/ccgus/fmdb) This library to simplify the operation of SQLite, so you do not have to spend a lot of experience to understand SQLite C API.

2.15 Change Xib to storyboard.

When you load a XIB , everything is placed in memory, including any images. If you have a view that is not immediately available, you are wasting valuable memory resources.

storyboards is another thing, storyboard. Instantiate a view controller only when needed.

When loading xib, all pictures are cached, and if you are doing OS X development, the sound files are also. Apple's description in the relevant documentation is:

当你加载一个引用了图片或者声音资源的nib时,nib加载代码会把图片和声音文件写进内存。在OS X中,图片和声音资源被缓存在named cache中以便将来用到时获取。在iOS中,仅图片资源会被存进named caches。取决于你所在的平台,使用NSImage 或UIImage 的`imageNamed:`方法来获取图片资源。

Obviously, the same thing happened in storyboards, but I didn't find any documentation to support this conclusion.

In addition, it is important to quickly open the app, especially when the user opens it for the first time, and the first impression is too important for the app.

All you can do is make it do as many asynchronous tasks as possible, such as loading the remote or database data and parsing the data.

Or that sentence, avoid too large a xib, because they are loaded on the main thread. So try to use storyboards without this problem!

注意,用Xcode debug时watchdog并不运行,一定要把设备从Xcode断开来测试启动速度
2.16 Learn to create autorelease Pool manually

NSAutoreleasePoolResponsible for releasing the autoreleased objects in block. In general, it is automatically called by the Uikit. But there are situations where you need to create it manually.

If you create a lot of temporary objects, you will find that the memory has been reduced until the objects are release. This is because the memory will only be released when the Uikit runs out of Autorelease pool.

The good news is that you can create temporary objects in your own @autoreleasepool to avoid this behavior:

NSArray *urls = [@"url1",@"url2"];forin urls) {    @autoreleasepool {        NSError *error;        error: &error];        thestringand autoreleasing more objects. */    }}

This code releases all Autorelease objects after each traversal

iOS Performance Tuning Summary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.