Instruments的用法 ios

How to Use Instruments in Xcode

Matt Galloway  Matt Galloway 

This post is also available in: FrenchSpanish

This is a blog post by iOS Tutorial Team member Matt Galloway, founder of SwipeStack, a mobile development team based in London, UK. You can also find me on Google+.

Learn how to troubleshoot and optimize your code with Xcode Instruments!

Learn how to troubleshoot and optimize your code with Xcode Instruments!

At this point in your iOS development career, you’ve probably written an app or two, and you are no doubt wondering what you can do to make your apps even better.

Besides improving your app by adding features, there is one thing that all good app developers should do… instrument their code!

This tutorial will show you how to use the most important features of the tool called Instruments that ships with Xcode. It allows you to check your code for performance issues, memory leaks, or other problems.

In this tutorial you’re going to learn:

  • How to detect and fix memory management issues in your code using the allocations and leaks instruments, and
  • How to determine hot-spots in your code using the time profiler instrument and how to make your code more efficient.

Note: This tutorial assumes that you are competent in Objective-C and iOS programming. If you are a complete beginner to iOS programming, you may wish to check out some of the other tutorials on this site. This tutorial makes use of a storyboard, so make sure you’re familiar with the concept; a good place to start is with the tutorial on this site.

This tutorial will be using Xcode 4.5, so make sure you’re fully updated to the latest version, which is available through the Mac App Store.

All set? Get ready to dive into the fascinating world of Instruments! :]

Getting Started

For this tutorial you won’t go through the process of creating an application from scratch; instead, a sample project has been provided for you. Your task is to go through the application and improve it using Instruments as your guide — very similar to how you would go about optimizing your own apps!

Download the starter project then unzip it and open it up in Xcode.

Build and run the app, perform a search, click the result, and you’ll see something like the following:

The starter project for this tutorial

Browse through the application and check out the basic functions. As you can see, the core feature of the app is to search and display photos on Flickr. There is a search bar at the top of the app, and when you perform a search, a new row of results appear in the table.

This new row in the table displays the search term, and the number of results found in parentheses. If you tap on a cell, the search results expand and present you with another table, displaying the image titles along with preview images.

If you tap on one of the preview results, the app takes you to a full screen view of the image. From that view, you can then rotate the image if desired.

So far so good! :] You can see that the app works as designed. You might be tempted to think that once the UI looks great the app is ready for store submission. However, you’re about to see the value that using Instruments can add to your app.

The remainder of this tutorial will show you how to find and fix the issues that still exist in the app. You’ll see how Instruments can make debugging problems a whole lot easier ! :]

Time for Profiling

Lots of developers start out with a vague idea that their app should go fast – and it’s a worthy aim. Then they read about something called “premature optimisation” and wonder how this terrible thing that the greybeard programmers frown at might be avoided. In the worst case, the novice developers forget about optimisation altogether!

To some extent, you can leave optimisation out of your app development process; only ten years ago, mobile devices were incredibly limited, and even the use of floating point numbers was forbidden because it made code size larger and calculations move at glacial speed.

Now, you hold an incredible amount of power in your pocket, complete with 3D hardware good enough to beat the best desktop hardware of not so long ago. But you can’t always depend on hardware and processor speed to gloss over the inefficient bits in your app.

So what is “profiling”, anyway? Profiling is a means of measuring. The output of a profiling session provides insight into which parts of your code are used most often; in turn, that tells you which parts of the code you should try to improve.

You can spend a week fine-tuning an interesting algorithm, but if that code only occupies 0.5% of total execution time, nobody will ever notice the difference, no matter how much you improved it. If instead you spent the effort optimising the loop where your program spends 90% of its time, and made only a 10% improvement, chances are your update will attract five star reviews because it will feel so much faster!

The first lesson of optimisation is: find the right places to do it! :]

Premature optimisation, you will have guessed by now, is spending time optimising the bits that really don’t matter in the end.

The first instrument you’ll look at is the “Time Profiler”. At measured intervals, the execution of the program is halted, and a stack trace is performed on each running thread. Think of it as pressing the pause button in Xcode’s debugger.

Here’s a sneak preview of the Time Profiler:



This screen displays the call stack of each thread. Each level, or frame, as it is called, is a different method the program’s execution path has followed to arrive at the point where the CPU is currently executing the code – that is, frame 0.

The time spent in each method can then be determined from the number of times the profiler is stopped in each method.

For instance, if 100 samples are done at 1 millisecond intervals, and a particular method is found to be at the top of the stack in 10 samples, then you can deduce that approximately 10% of the total execution time — 10 milliseconds — was spent in that method. It’s a fairly crude approximation, but it works!

So without any further ado, time to get instrumenting!

From Xcode’s menu bar, select ProductProfile, or press ⌘I. This will build the app and launch Instruments. You will be greeted with a selection window that looks like this:

These are all different templates that come with Instruments.

Select the Time Profiler instrument and click Profile. This will launch the iOS simulator and start the app. You may be asked for your password to authorise Instruments to analyse other processes — fear not, it’s safe to provide here! :]

In the Instruments window, you can see the time counting up, and a little arrow moving from left to right above the graph in the center of the screen. This indicates that the app is running.

Now, start using the app. Search for some images, and drill down into one or more of the search results. You have probably noticed that going into a search result is tediously slow, and scrolling through a list of search results is also incredibly annoying – it’s a terribly clunky app!

Well, you’re in luck, for you’re about to embark on fixing it! However, you’re first going to get a quick run down on what you’re looking at in Instruments.

First, make sure the view selector in the toolbar has all three options selected, like so:

That will ensure that all panels are open. Now study the screenshot below and the explanation of each section beneath it:


  1. These are the recording controls. The middle red button will stop & start the app currently being profiled when it is clicked. This is actually stopping and starting the app — not pausing it.
  2. This is the run timer and run navigator. The timer counts how long the app being profiled has been running. The arrows move between runs. If you stop and then restart the app using the recording controls, that would start a new run. The display would then show “Run 2 of 2”, but you could get back to the data of the first run by first stopping your current run, then pressing the left arrow to go back.
  3. This is called a track. In the case of the time profiler template you selected, there’s just one instrument so there’s just one track. You’ll learn more about the specifics of the graph shown here later in the tutorial.
  4. This is the extended detail panel. In the case of the time profiler instrument, it’s used to show stack traces, as that is what Instruments is recording.
  5. This is the detail panel. It shows the main information about the particular instrument you’re using. In this case, it’s showing the methods which are “hottest” — that is, the ones that have used up the most CPU time.

    If you click on the bar at the top which says “Call Tree” (the left hand one) and select “Sample List”, then you are presented with a different view of the data. This view is showing every single sample. Click on a few samples, and you’ll see the captured stack trace appear in the extended detail panel.

  6. This is the options panel. You’ll be learning more about these options shortly.

Now onto fixing the clunky UI! :]

Drilling Deep

Perform an image search, and drill into the results. I personally like searching for “dog”, but choose whatever you wish – you might be one of those cat people! :]

Now, scroll up and down the list a few times so that you’ve got a good amount of data in the time profiler. You should notice the numbers in the middle of the screen changing and the graph filling in; this tells you that CPU cycles are being used.

You really wouldn’t expect any UI to be as clunky as this; no table view is ready to ship until it scrolls like butter! To help pinpoint the problem, you need to set some options on the time profile perspective.

Under the Call Tree section on the left, select Separate by ThreadInvert Call TreeHide System Libraries and Show Obj-C Only. It will look like this:

Here’s what each option is doing to the data displayed in the table to the right:

  • Separate by Thread: Each thread should be considered separately. This enables you to understand which threads are responsible for the greatest amount of CPU use.
  • Invert Call Tree: With this option, the stack trace is considered from top to bottom. This means that you will see the methods in the table that would have been in frame 0 when the sample was taken. This is usually what you want, as you want to see the deepest methods where the CPU is spending its time.
  • Hide Missing Symbols: If the dSYM file cannot be found for your app or a system framework, then instead of seeing method names (symbols) in the table, you’ll just see hex values. These correspond to the address of the instruction within the binary code. If this option is selected, then these are hidden, and only fully resolved symbols are displayed. This helps to declutter the data presented.
  • Hide System Libraries: When this option is selected, only symbols from your own app are displayed. It’s often useful to select this option, since usually you only care about where the CPU is spending time in your own code – you can’t do much about how much CPU the system libraries are using!
  • Show Obj-C Only: If this is selected, then only Objective-C methods are displayed, rather than any C or C++ functions. There are none in your program, but if you were looking at an OpenGL app, it might have some C++, for example.
  • Flatten Recursion: This option treats recursive functions (ones which call themselves) as one entry in each stack trace, rather than multiple.
  • Top Functions: Enabling this makes Instruments consider the total time spent in a function as the sum of the time directly within that function, as well as the time spent in functions called by that function. So if function A calls B, then A’s time is reported as the time spent in A PLUS the time spent in B. This can be really useful, as it lets you pick the largest time figure each time you descend into the call stack, zeroing in on your most time-consuming methods.

Although some values may be slightly different, the order of the entries should be similar to the table below once you have enabled the options above:

Well, that certainly doesn’t look too good. The vast majority of time is spent in the table cell that sets the photo. That shouldn’t come as too much of a shock to you, as the table scrolling was the clunkiest part of the UI, and that’s when the table cells are constantly being updated.

To find out more about what’s going on within that method, double click on the row. Doing so will bring up the following view:

Well that’s interesting, isn’t it! Almost three-quarters of the time spent in the setPhoto: method is spent creating the image data for the photo!

Now you can see what the problem is. NSData’s dataWithContentsOfURL blocks (that is, does not return) until the data has been downloaded. Since this request goes out to the internet to grab the data, each call could take up to a few seconds to return. This method is run on the main thread, and therefore the entire UI is blocked from updating whilst the image data is downloaded.

To solve this, a class has been provided called ImageCache which allows asynchronous downloading of images on a background thread. The code exists in the PhotoCell class.

You could now switch to Xcode and manually find the file, but Instruments has a handy “Open in Xcode” button right in front of your eyes. Locate it in the panel just above the code and click it:

There you go! Xcode opens up at exactly the right place. Boom!

Now, comment out the two lines which grab the NSData and set the image, and uncomment the block of code below. The setPhoto method will then look like this:

- (void)setPhoto:(FlickrPhoto *)photo {
    _photo = photo;
 
    self.textLabel.text = photo.title;f
 
//    NSData *imageData = [NSData dataWithContentsOfURL
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值