iOS tutorial instruments to test your app

Source: Internet
Author: User
Tags stack trace

Compared with a lot of instruments or found that the foreigner wrote more. So decisive translation. Able to see the original English, encourage everyone to see the original material away from the second-hand tutorial. This is the original.

Entry

In order to save everyone's time, provide a demo of the demo to everyone. Code portal.

Download and unzip and open with Xcode.

After compiling and running the app and entering any words in the search box, click on the results and you will see the following results

As you can see, this app is very simple. The program actually calls the Flickr API, and after searching through the search box on the top of the app, the search term is displayed in the following TableView, with the number of search results in parentheses after the search term, click on this line to enter a list of results on a slightly more graphic page. For example, click on one of the lines to enter the image's big picture mode, where you can rotate the image as needed.

So far the page looks pretty much, and you might think you should be able to submit appstore directly. The next article will teach you instruments tools to improve the performance and stability of your app.

"Time Detector"

The World martial arts, only fast not broken. Many companies believe in this dogma. The app's compaction cycle can be squeezed to the minimum, which leads to a lot of problems in the development, a bit of experience with the engineer sloppy optimization, and worse, the inexperienced engineers will not even optimize the app.

In some ways, performance optimizations can be overlooked in your development process. Ten years ago, the hardware resources of mobile devices were very limited. Even floating-point numbers are banned. Because floating-point numbers can cause the code to become larger and slower to calculate.

With the rapid development of science and technology, hardware can largely compensate for the software's short board. Now the mobile device 3D hardware processing efficiency is even comparable to the PC, but you can not always rely on hardware and processor speed to cover up your app to do more garbage. (if Android is running on iphone, can it be as smooth as iOS?)

The concept of performance is very well drawn, so we have to rely on the graphical output of the data. You may spend a week optimizing an interesting algorithm, but this algorithm only accounts for 0.5% of the total execution time, no matter how much effort you take to optimize it, no one will notice. Instead a For loop takes 90% of the time, You can improve the efficiency by a little change, that is, this simple change can get a lot of goodwill. Because. The first thing they feel when they run the app is a lot faster than before. No one's going to care what you're modifying is a much better algorithm, or a simple for loop.

What does this mean?

Instead of taking the time to optimize small details, you might as well find a place to change your optimization in more time.

Here's the first tool, "Time Event Viewer" (your own fictional name, English-time Profiler),——— He can measure the interval of time, interrupt the execution of the program, and track the stack of each thread. You can imagine when you press the pause screen when Xcode is debugging

For example, 100 samples are doing a 1 millisecond interval, and then there are 10 samples at the top of a method stack, and you can figure out that the approximate amount of time is 10% 10 milliseconds spent in this method, which is an approximation.

Needless to say, time is a detection.

Choose Product-profile from the Xcode menu, or choose?

The program will start instruments, and you will see a selection window

This is instruments all the test instrument panel, select "Timer profilter" click "Profile" back to the Qidong simulator and app, you will be asked to enter the password once, so that instruments can have permission to intercept this process.

In the tool window, you can see the time count and leave a small arrow moving to the right of the graphic above the center of the screen. This indicates that the application is running.

Now that you're running the app and searching for some pictures, you find that finding a result is too slow, and the Search results list page can be unbearable to scroll.

First, make sure that the view in the toolbar selects all of the three options selected, as follows:

This will ensure that all the panels are open. Now, study the explanations below and each of the sections below it:

1. Record control button. The middle of the red button will stop with the startup it is clicked on when the application is currently being analyzed. Note that this is actually stopping and starting the application instead of pausing it.

2. Run the timer and run the navigation, the timer shows how long the app has been running, and the arrows can be moved. If you stop and then use the Record button to restart the application, this will start a new run. The display will display "Run2 of 2", you can go back to the first run of data, first you stop the current run, and then press the left arrow back.

3. Run the track.

4. Expansion panel, in the case of a time-sniffing instrument, it is used to track the display stack.

5. Panel in detail. It shows the main information about the instrument you are using, which is the most frequently used department, where you can see how long the CPU is running.

6. Options panel, described later.

The play is coming.

Bottom

Perform an image search and delve into the results. I personally like to look for "dog", of course you can also choose any content you want. Like a cat, a beautiful girl, something.

Now scroll up and down the list, let the time detector measure the data, and pay attention to the changes and values of the screen. These values reflect the CPU cycle.

But you may find that the following values are too many to see your dazzling. Next, open the left call tree and press the configuration below

The following configuration options are described below:

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. Therefore, if function A calls B, then A's time is reported in a time spent plus B. This is really useful, because it allows you to pick the maximum time number to go to the call stack each time, zeroing in on your most expensive method.

If you have enabled the above options, although some values may be slightly different, the order of the following results should be similar to the following table:

Through the above you can see most of the time spent in updating the form of photos.

Double-click this line, and you will see the following

Well, that's interesting, isn't it! Almost three-fourths of the time spent in Setphoto: methods are spent creating image data for photos!

Now you can see what the problem is, the NSData's Datawithcontentsofurl method does not return immediately, because to go to the data from the Internet, each call takes up to a few seconds to return, and this method runs in the main thread, it is conceivable what results.

In fact, in order to solve this problem, the class provides a Imagecache method for the background asynchronous download.

Now you can switch to Xcode and manually locate the file, but the instrument has a handy "open Xcode" button right in front of you. Find its panel just above the code and click on it:

Changes like the following

1234567891011121314 - (void)setPhoto:(FlickrPhoto *)photo {    _photo = photo;     self.textLabel.text = photo.title;f  //    NSData *imageData = [NSData dataWithContentsOfURL:_photo.thumbnailUrl]; //    self.imageView.image = [UIImage imageWithData:imageData];     [[ImageCache sharedInstance] downloadImageAtURL:_photo.thumbnailUrl                                  completionHandler:^(UIImage *image) {                                      self.imageView.image = image;                                      [self setNeedsLayout];                                  }];}

After you have modified it, rerun the application Product-profile (or cmd-Remember, these shortcuts will really save you some time).

Please note that this time will ask again if you are using together. This is because you also have a window to open this program, and the instrument assumes you want to run again with the same options.

Perform some more searches, and note that the user interface is not so much at this time! These images are now loaded asynchronously and cached in the background, so once they have been downloaded once they do not have to be downloaded again.

It looks great! Is it time to release it? Of course it's not.

Assign, assign, assign

The next instrument is the distribution tool. It gives you all the details of all the memory you create and store them, and it also shows that you keep a count of each object.

Turn off the instrument, go back to Xcode and select Product->profile. Then, assign from selector and click Profile. Such as:

The program opens again and you'll see

This time you will find two tracks. One is called (assigned) allocations, and one is called VM Tracker (virtual machine tracking). This allocation track will be discussed in detail in this tutorial; Virtual machine Tracing is also useful, but more complex.

So your mistakes are going to be tracked down?

There are hidden items, you may not know there is something there. You may have heard of a memory leak. But what you may not know is that there are actually two kinds of leaks.

The first is a true memory leak, an object that has not been released, but is no longer referenced. Therefore, the memory cannot be reused.

The second type of leakage is more troublesome. This is called "unbounded memory Growth". This occurs when the memory continues to be allocated and never has the opportunity to be released.

If this goes on forever your program will take up an infinite amount of memory and will be killed by the system's watchdog when it exceeds certain memory.

Create a scene where you can detect unlimited memory growth. First, the application makes 10 different searches (do not use an already existing search). Make sure to search for some results! Now let the program wait a few seconds.

You should have noticed that the orbital graph in the distribution is constantly rising. This is telling you that the memory has been allocated. It's this feature that will guide you to find unlimited memory growth.

What you are going to do is "heap shot analysis". To do this, press the button called "Mark Heap". You will find the detail panel to the left of the button

Press it and you will see a red sign appearing on the track, like this:

The purpose of the heap shot analysis is to perform an action multiple times to see if memory is growing indefinitely. Search for a content, wait a few seconds to load the image, and then return to the home page. Then mark the heap again. Repeat this to do different searches.

After a few searches, the instrument will look like this:

You should be in doubt at this point. The blue in the picture is going on, you continue to do this 10 times the search for Blue also keeps getting taller:

That must be bad. Don't worry, what's the memory warning? You know all this, right? Memory warning is to tell an application that memory warnings are the best way for iOS to process apps, especially when memory is getting tighter and you need to clear some memory.

Memory growth is not necessarily your code in addition to the problem, it may be the UIKIT system framework itself caused.

Simulate a memory warning in the iOS Emulator's menu bar by selecting the Hardwaresimulate memory warning. You will find that memory usage comes down slightly, but definitely not back to what it should be. So there is an infinite amount of memory where the growth takes place.

The reason for the heap shot is to do the drilling search for each iteration, and you can see the memory allocated between each shot. Take a look at the details panel and you'll see a bunch of shots.

Select the Hardwaresimulate memory warning in the menu bar of the iOS emulator to simulate a memory warning. You'll notice a slight drop in memory usage, but certainly not back where it should be.

After every search done you can see the allocations between the memory has been shot. Take a look at the details panel and you'll see a lot of shots.

Steady and ruthless

The first stack of shots as a reference, and then casually open a heap of shots, you will see the following:

Damn, this is a big object! Where do you start looking?

The best way to do this is by listing the classes that you use directly in your application. In this case, Httpheaderdict,cgregion,cgpath,cfnumber, and so on, can be ignored.

However, one of the highlights is UIImage, which is definitely used in your program. Click on the arrow on the left of UIImage to display the full list. Select one, in the extension details panel:

The gray is the system library, the black part is your application code, to get this tracking more context, double-click the unique black box Imagecache method, this time will be reversed to the following method:

123456789101112131415 - (void)downloadImageAtURL:(NSURL*)url completionHandler:(ImageCacheDownloadCompletionHandler)completion {    UIImage *cachedImage = [self imageForKey:[url absoluteString]];    if(cachedImage) {        completion(cachedImage);    else{        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{            NSData *data = [NSData dataWithContentsOfURL:url];            UIImage *image = [UIImage imageWithData:data];            [self setImage:image forKey:[url absoluteString]];            dispatch_async(dispatch_get_main_queue(), ^{                completion(image);            });        });    }}

Tools are very useful, and you now have to try to think through your own code what's going on. Look through the above method, you will see that it calls a method named SetImage: Forkey:. This method is cached in case it is used again after the image of the application. Ah! Then this certainly sounds like it might be a problem!

Let's take a look at the implementation of this method:

123 - (void)setImage:(UIImage*)image forKey:(NSString*)key {    [_cache setObject:image forKey:key];}

To download a picture from the Web to add a dictionary, you will notice that these pictures have never been clear from the dictionary.

That's why memory keeps growing because applications don't delete things from the cache. It will only increase them all the time.

To resolve this issue, you need to Imagecache receive a uiapplication memory crunch warning. Clean up the cache.

To enable Imagecache to receive notifications, modify the Init method as follows:

1234567 - (id)init {    if((self = [superinit])) {        _cache = [NSMutableDictionary new];        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(memoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];    }    return self;}

Register Uiapplicationdidreceivememorywarningnotification Execute memorywarning: method.

123 - (void)memoryWarning:(NSNotification*)note {    [_cache removeAllObjects];}

Memorywarning deletes all objects in the cache. This will ensure that the image is not held.

In order to test this fix, start the instrument again (with CMD in Xcode) and repeat the steps. Do not forget to end the memory warning in the simulation!

Note: Make sure you exit from Xcode and rebuild instead of just clicking on the red button on the instrument to make sure you're using the latest code.

This analysis should look like this:

At this time, memory is subject to a sharp drop in memory warnings. But there is still some memory overall growth, but not as much as it used to be.

The reason is still a certain growth is due to the system library, and there is not much to do. It appears that the system library does not release all memory, which may be by design or may be an error. What you can do in your app is to release as much memory as possible and you've done it!

Good job! There is also a problem, patched up,-there is still a leak and you haven't solved the first type of problem.

Memory leaks

Memory leaks of the instrument. This is used to find the first class of leaks mentioned earlier-the kind that occurs when an object is no longer referenced.

Detecting leaks is a very complicated thing to understand, but the leaking tool remembers all objects that have been allocated, and periodically scans each object to determine if there is anything that cannot be accessed from any other object.

Turn off the instrument, go back to Xcode and select Product->profile

Back to your app! Perform a search to get the results. Then click the Preview line of the result to open the full screen browser. Press the Rotate button in the upper-left corner, and then press again.

Back to the instrument, wait a moment. If you have completed the above steps correctly, you will find that the leak has already appeared! Your tool window will look like this:

Return to the simulator and press the spin several times. Then return to the instrument and wait, and get the following result:

Where did the leak come from? Extended Details panel

In the extended Details panel, open the Cgcontext list. Select one of the elements on the cgcontext in the list, which indicates the resulting object to be created, such as the following stack trace:

Again, the frames involved in your code appear as black. Because there is only one, double-click it to see the code method.

The problematic approach is rotatetapped: This is the handler that is invoked when the spin button is tapped. This method rotates the original image and creates a new image, as follows:

123456789101112131415161718192021222324 - (void)rotateTapped:(id)sender {    UIImage *currentImage = _imageView.image;    CGImageRef currentCGImage = currentImage.CGImage;     CGSize originalSize = currentImage.size;    CGSize rotatedSize = CGSizeMake(originalSize.height, originalSize.width);      CGContextRef context = CGBitmapContextCreate(NULL,                                                 rotatedSize.width,                                                 rotatedSize.height,                                                 CGImageGetBitsPerComponent(currentCGImage),                                                 CGImageGetBitsPerPixel(currentCGImage) * rotatedSize.width,                                                 CGImageGetColorSpace(currentCGImage),                                                 CGImageGetBitmapInfo(currentCGImage));     CGContextTranslateCTM(context, rotatedSize.width, 0.0f);    CGContextRotateCTM(context, M_PI_2);    CGContextDrawImage(context, (CGRect){.origin=CGPointZero, .size=originalSize}, currentCGImage);     CGImageRef newCGImage = CGBitmapContextCreateImage(context);    UIImage *newImage = [UIImage imageWithCGImage:newCGImage];      self.imageView.image = newImage;}

Again, the instrument can only give you a hint here, where the problem is, it can't tell you the exact location of the leak. This is the only place where you can prove that you are creating an object leak. You may think that arc and there is no way to cause a memory leak in the code ... Right?

Recall that arc only deals with Objective-c objects. It does not manage the release of reserved and Corefoundation objects instead of Objective-c objects.

Ah, now it's starting to become obvious what's the problem?

-cgcontextref and Cgimageref objects will never be released! To solve this problem, add the following two lines of code at the end of the Rotatetapped method:

12 CGImageRelease(newCGImage);CGContextRelease(context);

Both of these calls need to maintain a count of the retention of both objects. This description, you also need to understand the reference count-even if you use the arc! in your project

From Xcode, use the CMD tool to build and run the application.

In the use of leak instruments then look at the application and see if the leaks are fixed. If you follow the above steps correctly, the leak should disappear!

Use instruments for iOS tutorials to test your app

Related Article

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.