Dec 29

On the eve of the decade I thought it might be fitting with a cautionary tale about dates and time.

An iPhone app that I was developing had to send data to a server. Among the data items was a timestamp.

As a best practice during development, the app was tested on several types of devices with different versions of the OS. It was working great. Except on one particular iPhone.

There was nothing obviously different about this device. Same hardware and same OS as on other devices that were working fine. We restarted the device and reinstalled the app several times. Still it refused to communicate properly with the server.

I’ll spare you the details of the hours of debugging that followed, and skip directly to the solution…

Sending timestamps between different systems is a common area of confusion and errors. For this app we had settled on expressing the time in the number of seconds since the Unix epoch (January 1, 1970). This value was then to be sent as a URL parameter in a HTTP GET request. This is a convenient way to transmit a timestamp between systems since most programming languages have ways to create a date + time object from this long value.

If you print out [[NSDate date] timeIntervalSince1970] you will see a 10 digit number. And that was what the server was expecting. However, if you look at the number (1262122135 as I’m writing this) you’ll notice that it wasn’t that long ago when the value went from 9 to 10 digits. In fact, this happened on the 9th of September 2001 at 01:46:40 GMT.

Upon further examination the obstinate iPhone that refused to run the app correctly, had its system clock set to early 2001. Thus the server call contained a 9 digit timestamp, instead of the expected 10 digits. This caused the failure when running the app.

The moral of the story: Never trust any data that you do not fully control. User input is a category that is so obvious that most developers always validate it. The system clock can also be set by the user and should therefore not be implicitly trusted.

written by Nick \\ tags: ,

Apr 03

My previous post about conditional logging received quite a few responses, with several people pointing out that littering your code with #ifdef DEBUG statements is both ugly and error prone. Karl Kraft, for example, created a new DebugLog class as a drop-in replacement for NSLog.

Since NSLog has been around for quite a while, there have been many solutions to this problem.

CocoaDev suggests this macro:

#if MY_DEBUG_FLAG
#define DEBUG_OUTPUT( a )         NSLog( a )
#define DEBUG_OUTPUT1( a, b )     NSLog( a, b )
#else
#define DEBUG_OUTPUT( a )         // (a)
#define DEBUG_OUTPUT1( a, b )     // (a,b)
#endif

Enumerating all the variants with different number of parameters gets a bit tedious, so with Objective-C 2.0 C99 you can use varargs macros:

#define DEBUG_OUTPUT(fmt, ...) NSLog(fmt, ## __VA_ARGS__)

As described by Fraser Hess in Dropping NSLog in release builds you can put this in your <AppName>_Prefix.pch file:

#ifdef DEBUG
#    define DLog(...) NSLog(__VA_ARGS__)
#else
#    define DLog(...) /* */
#endif
#define ALog(...) NSLog(__VA_ARGS__)

Use ALog for cases where you always want log output regardless of the state of the debug flag. I like this preprocessor macro approach because you don’t have to carry around extra classes in all your projects. Just a few lines of code to paste into one file in your project.

But I think we can improve it further.

The built-in macro __PRETTY_FUNCTION__ is pretty nifty in that it outputs the name of the class and the method where it’s running. Mark Damon Huges uses this in his Cocoa logging macro:

#ifdef DEBUG
// DLOG takes a format argument (which must begin %s) and 0 or more args:
// DLOG(@"%s");
// DLOG(@"%s: %d", x);
#define DLOG(fmt, ...) NSLog(fmt, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#else
#define DLOG(...)
#endif

A drawback with this macro is that it requires you to add a “%s” to all your log statements, e.g. DLOG(@”%s foo”); instead of NSLog(@”foo”);. So it’s not a drop-in replacement for NSLog.

Let’s try to fix that.

#define DLog(fmt, ...) NSLog((@"%s " fmt), __PRETTY_FUNCTION__, ##__VA_ARGS__);

Now you can do DLog(@”foo”); as well as pass in parameters like DLog(@”value: %d”, x);

One final touch is to add the line number:

#define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

Now if you’re lazy and you want to know that execution has reached a particular line, you can just use DLog();

So here is the complete listing of the macro:

// DLog is almost a drop-in replacement for NSLog
// DLog();
// DLog(@"here");
// DLog(@"value: %d", x);
// Unfortunately this doesn't work DLog(aStringVariable); you have to do this instead DLog(@"%@", aStringVariable);
#ifdef DEBUG
#	define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#	define DLog(...)
#endif

// ALog always displays output regardless of the DEBUG setting
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

Set the DEBUG variable in your project as described previously. Update: If your project is 3.0 you may need to set the DEBUG variable this way.

I’m sure there will be further improvements to this. Comments are open as always.

written by Nick \\ tags:

Mar 06

A simple method to debug your iPhone application code is to use NSLog() statements at strategic points. I often find myself printing out the response from server calls using NSLog. Even after the iPhone client development is done, these log statements can be useful to debug server issues. But you obviously don’t want to fill the console log in your released code.

To skip lines of code you don’t want to include in the release build you can use a preprocessor instruction:

#ifdef DEBUG
NSLog(@"Server Response: %@", response);
#endif

Unfortunately Xcode does not automagically define DEBUG when you do a debug build. So you have to add a definition to your project target.

1. Be sure you select Debug in the Configuration drop down.

2. Select Settings Defined at This Level in the second drop down to reduce the number of fields shown.

3. Now click the tool button in the bottom left corner and select Add User-Defined Setting from the menu.

4. Enter the following name value pair:
OTHER_CFLAGS    -DDEBUG=1

Now when you build and run in debug configuration you will see the log messages, but those lines of code will not be included in your release builds.

Update: Use GCC_PREPROCESSOR_DEFINITIONS instead of OTHER_CFLAGS. See comments below.

Update 2: See this post for a vastly improved method: The Evolution of a Replacement for NSLog

Update 3: See this post if you’re working with an SDK 3.0 project: How To Add DEBUG Flag In A 3.0 Project In Xcode

written by Nick \\ tags: