Tampilkan postingan dengan label Debugging. Tampilkan semua postingan
Tampilkan postingan dengan label Debugging. Tampilkan semua postingan

Kamis, 16 September 2010

Global Symbolic Breakpoints in Xcode 4

It wasn't obvious to me how to set a global symbolic breakpoint in Xcode 4. I stumbled across the answer today. Because Xcode 4 is still under NDA, I can't post this here, so instead, I wrote it up on Apple's Dev Forums (Dev Center login with beta access required).

Senin, 10 Mei 2010

PSA: Respect the Main Thread

I tweeted this earlier as a joke, but it's actually a very serious thing. I've had several jobs in the last year where I've been asked to look at and either suggest fixes or actually fix iPhone applications written by other developers. One thing that I've seen several times in code I've reviewed is something like this littered throughout the application:

[NSThreadsleepForTimeInterval:0.3];

This code causes the thread it's called from the do nothing for the specified length of time. Then I'll look through the code for some indication that the application is spawning threads. So far, in every case, the app hadn't spawned any threads, explicitly, or implicitly using NSOperationQueue. If you haven't detached any threads, and you call sleepForTimeInterval:, you are sleeping the application's main thread, and that is a very bad thing to do.

Usually, I see these sleepForTimeInterval: calls in applications that do some kind of asynchronous network communication. My guess is that the developers who wrote these applications came from Java, .Net, or some other language where network communication is commonly handled on a non-main thread. In those languages, it's not uncommon to see code that puts the network worker thread to sleep or into a loop to make it wait for a response and account for any potential lag time. It's not a great approach, but in these environments, it generally works.

In Cocoa and Cocoa Touch, however, unless you specifically spawn a thread and register your network communications with the spawned thread's run loop, your network communications using CFNetwork as well as any networking done using the built-in networking functionality that exists in many Cocoa classes all happens on the main thread.

Another related problem that I sometimes see is something like this:

- (IBAction)soSomething
{
NSData *data = [NSDatadataWithContentsOfURL:[NSURLurlWithString:@"http://foo.com/reallybigdatafile"]];
while(1)
{
// parse really big data file and break when done
}

}

This code has a few really bad things going on. It's important to keep in mind that IBAction methods always fire on the main thread. So, the first problem is the call to dataWithContentsOfURL:. This is what's called a blocking network operation, which means that calling this method will prevent any further code on this thread from executing until all the data has been received because the method will not return until that has happened. The same thing is true for all of the convenience constructors that contain withContentsOfURL: in their name. While you can probably get away with very limited use of these methods for very small pieces of data, you really should be only using asynchronous network calls in your apps. You can't predict how long network communications will take, even with tiny pieces of data. If the radios are powered down, EDGE connections can take several seconds to re-establish, which is long enough that your user will probably notice the freeze.

The second problem with this thread is the while loop. Small loops are often okay in action methods, but those that could potentially be large or where the length of the loop is simply impossible to know (which is typically the case with while (1) or while(TRUE) loops), you don't want to be doing the processing on the main thread.

Why All This is Bad


If you sleep the main thread, quite literally nothing can happen in your app except for background thread execution. If you haven't spawned any background threads, then pretty much nothing can happen at all. Your user interface will freeze up and your user won't be able to use the application. Buttons won't highlight when tapped and animations will freeze in place. But it's even worse than the interface freezing (which is certainly bad enough), all event processing and network communications will freeze up also. Anything that is handled by your application's main event loop simply doesn't happen while the main thread is asleep.

I have yet to see a situation where calling sleepForTimeInterval: on the main thread is a good idea.

If you perform a long-running operation on the main thread, your code will monopolize the main thread and the end result will be essentially the same as sleeping the main thread while your loop runs. No user interaction, no network communications, no animation.

If you want a good introduction on how to get stuff off your main thread, check out Dave Dribbin's blog post on concurrent operations. More iPhone 3 Development also devotes a full chapter to different types of concurrency.

Kamis, 14 Januari 2010

NSZombies in Instruments

If you've been an iPhone developer fro any length of time, you probably know about the eight wonder of the debugging world, NSZombie (if you don't, check out the last chapter of More iPhone 3 Development). What you may not know is that Instruments has recently added support for NSZombie. Mark Johnson has put together a little video showing how to use Instrument's NSZombie support right here.

Sabtu, 05 September 2009

Debugging Drawing

Apple has a nice little utility called QuartzDebug in /Developer/Applications/Graphics Tools, and one of the features of this program is that it will highlight all redrawing that gets done in every application. Every time a view is redrawn, it flashes. This is a great tool for determining if you're doing unnecessary drawing in your drawRect: method, or if you're somehow triggering unneeded redraws some other way.

I've had a lot of people ask me about doing this on the iPhone. I've been told by several people that they saw this functionality demonstrated at the iPhone tech talks, which had me stumped. I completely forgot that you can get very similar functionality by passing an argument called NSShowAllDrawing to your application on launch. This is mentioned in this excellent technote on debugging.

Michael Fey has a (somewhat holder) blog post, complete with video, that shows how to use NSShowAllDrawing. His example shows using it in a Cocoa application, but the process is exactly the same for using it in an iPhone application.

Update: A couple of people pointed out in the comments that this option is also available using Instruments. If you run with the Core Animation template, there's a checkbox labeled "Flash Updated Regions", which is checked in the screenshot below:



I haven't been able to get the Core Animation template to work for me on the Simulator, though. I'm not sure if that's by design, or a problem with my installation.

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Lady Gaga, Salman Khan