February 14th, 2007
I’m working on an application now that uses a custom document format. Since my code manipulates this format and spits it back out to disk, I find myself frequently examining the resulting documents using Peter Ammon’s excellent Hex Fiend to examine the resulting files, and make sure the content is still format-compliant.
But while I’m debugging the code that actually does the manipulation, I find myself stuck doing stupid stuff like:
(gdb) p/x ((char*)[imageData bytes])[14]
$1 = 0x28
Ugh! That’s no way to win the software wars. It occurred to me today that what I really want is something like Hex Fiend built right into the debugger. Why shouldn’t I be able to hex-dump my NSData objects directly from the console? It turns out I wasn’t alone in this wish, because Dan Wood recently published a category on NSData that allows just that.
By simply compiling the NSData category into a given application, you give NSData’s debugging description superpowers. For instance, here’s me at the gdb console, examining the contents of the favicon.ico response I just received from NSURLConnection:
(gdb) po imageData
NSData 350 bytes:
00 00 01 00 01 00 10 10 10 00 00 00 00 00 28 01 | ..............(.
00 00 16 00 00 00 28 00 00 00 10 00 00 00 20 00 | ......(....... .
00 00 01 00 04 00 00 00 00 00 C0 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF | ................
FF 00 00 00 FF 00 00 00 EF 00 00 00 DE 00 00 00 | ................
CE 00 00 00 BD 00 00 00 AD 00 00 00 9C 00 00 00 | ................
8C 00 00 00 7B 00 00 00 52 00 00 00 42 00 00 00 | ....{...R...B...
29 00 00 00 10 00 00 00 00 00 00 00 00 00 11 11 | )...............
11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 | ................
11 11 11 11 11 11 13 31 11 11 12 55 21 11 1B B1 | .......1...U!...
13 D8 7F FF FB 31 1B B1 6F D4 FB 65 9F D2 1B DB | ....1..o..e....
FB 21 84 11 15 F5 1B FF FC 41 12 78 8D D1 1B B1 | .!.......A.x....
3C C1 2D FF FB 51 1B B1 1A D1 5F 71 11 11 1B C5 | < .-..Q...._q....
BF 81 1C C7 58 61 1A FF C6 11 12 BF FF 81 12 54 | ....Xa.........T
11 11 11 13 52 11 11 11 11 11 11 11 11 11 11 11 | ....R...........
11 11 11 11 11 11 11 11 11 11 11 11 11 11 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ..............
Current language: auto; currently objective-c
(gdb)
Dan’s code is pretty much perfect as-is, but I couldn’t resist tacking on some additional features. His category hardcodes the dumped data to 1024 bytes, but in my case there are times when I’m interested in seeing more. I added two category methods to the mix:
// startOffset may be negative, indicating offset from end of data
- (NSString *)descriptionFromOffset:(int)startOffset;
- (NSString *)descriptionFromOffset:(int)startOffset
limitingToByteCount:(unsigned int)maxBytes;
Now I can peek at a specific subrange, or expand the default limit of 1024 bytes. I can even peek at the end of a chunk of data, by specifying a negative offset:
(gdb) po [mDocumentData descriptionFromOffset:-11]
NSData 109 bytes (showing bytes 98 through 109):
02 43 41 54 41 54 4F 4E 49 43 00 | .CATATONIC.
(gdb)
Wow! This is a pretty huge addition to my debugging and development toolbelt. Many thanks to Dan Wood for providing the ready-made code to speed up my implementation.
NSData+RSHexDump is freely available to you, under an MIT license.
Posted in Cocoa, Debugging, Free Code, Hacking, Programming, Technology, Xcode | 9 Comments »
February 14th, 2007
John Gruber was recently featured for a second time on Dan Benjamin’s instantly-awesome Hivelogic Podcast.
I’m glad that Jesper heard and was intrigued by some of the same comments I was, because he reminded me that I wanted to comment on a subtle but worth-repeating impression that I took away.
The comments are those pertaining to the introduction of scripting language bridges as standard developer resources in Leopard OS X 10.5. Gruber points out that for developers, the presence of these scripting language bindings will both open up the platform to a wider audience of developers, and enable selective use of scripting languages where the highest performance is not necessary.
He suggests that a typical developer will write everything in Ruby or Python, and then do performance testing. Anything that needs a speed-up can be redone in Objective-C. You know, that “slow” dynamic variant of C :)
This analysis is foreboding, because it’s exactly what programmers have always done when they switched to a higher level language. 10 years ago a programmer would be more likely to “switch to assembly” for a much-needed performance boost. Has it come to this? Are we moving to a higher plane? If you’re like me, you’ve probably become quite comfortable in your Objective-C universe, and somewhat dismissive of the scripting languages as they begin to encroach on our holy ground. But we run the risk of being like those losers who still insist on programming everything in assembly, while the higher-level code would be just as fast and easier to maintain.
Is C the new assembly?
Posted in Cocoa, Hacking, Programming, Technology | 84 Comments »
February 12th, 2007
I’m working on an application that has some simple networking needs, among them fetching small bits of data off of a variety of user-configured web sites. Since the needs are so straight-forward I thought using NSURL and its “resourceDataUsingCache:” method would be the way to go. It so happens that this application already has a separate thread running when the data is needed, so the synchronous call is fine:
NSData* myWebData = [myURL resourceDataUsingCache:NO];
This works amazingly well and reliably returns the contents of the specified URL, exactly as you’d expect. Unless the server decided to zip encode the data! In this case, you’ll get back data that for all intents and purposes looks completely wacked.
The problem stems from the fact that NSURL’s data loading mechanism passes the following header to the server when requesting the URL:
Accept-Encoding: gzip, deflate
But when the server complies and returns the data, NSURL shrugs and passes it straight back to the caller, without doing us the favor of unzipping it.
Becky Willrich acknowledged the bug in NSURL a few years ago, and suggested using a lower level API to work around the problem. She also identified an insidious aspect to the bug, which is that a server won’t necessarily give you zipped data just because you offered to handle it. In fact, a server that is in the habit of giving zipped data may choose not to if there doesn’t seem to be a benefit to doing so. In particular, if the cargo is so small that it would be more trouble to zip it than to just send it.
So why am I writing about this? Mainly to publish a simple workaround to the problem, using a slightly more complicated set of classes and parameter values, but ultimately being almost as simple as the original:
NSError* theError;
NSURLResponse* theResponse;
NSURLRequest* urlRequest =
[NSURLRequest requestWithURL:myURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
NSData* myWebData =
[NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&theResponse
error:&theError];
Monitoring the situation with tcpdump from the command line, I see that the same zipped content is being requested and received, but evidently NSURLConnection is kind enough to perform the extra step of unzipping it for me. Whoo!
Note that the methods used require 10.2 with Safari 1.0 installed, or 10.2.7 or later.
Posted in Apple, Cocoa, Programming | Comments Off on Caught With My Bytes Unzipped
February 11th, 2007
OK … I mean this in the nicest possible way, because I have also considered (and may someday pursue!) writing my own ToDo-type application.
But I’d like to offer my revision on a popular joke from academia…
- Those who can, do
- Those who can’t do, write ToDo apps.
- Those who can’t write ToDo apps … eventually figure out how to do.
Posted in Humor, Technology, Usability | 8 Comments »