<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: The Evolution of a Replacement for NSLog</title>
	<atom:link href="http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/feed" rel="self" type="application/rss+xml" />
	<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog</link>
	<description>Tips and Tricks for iPhone, iPod, iPad and iOS Developers</description>
	<lastBuildDate>Sat, 28 Jan 2012 16:20:12 -0700</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: How To Download a File Only If It Has Been Updated &#124; iPhone Development Blog</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-14962</link>
		<dc:creator>How To Download a File Only If It Has Been Updated &#124; iPhone Development Blog</dc:creator>
		<pubDate>Wed, 02 Nov 2011 23:03:41 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-14962</guid>
		<description>[...] See this post for the source to the DLog [...]</description>
		<content:encoded><![CDATA[<p>[...] See this post for the source to the DLog [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Neal Ehardt</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-13450</link>
		<dc:creator>Neal Ehardt</dc:creator>
		<pubDate>Fri, 26 Aug 2011 23:57:51 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-13450</guid>
		<description>Great help, thank your for the blog post!  I&#039;m a bit of a perfectionist so here&#039;s the DLog that works for me.  It prepends your output with a fixed-length string consisting of the Time, Function, and Line.  For my purposes (a UI-heavy iOS client) these are the most relevant pieces of data.

Here&#039;s some sample output -- it looks much nicer in monospace.  Notice that the class name and message name are treated as separate strings, so a long class name won&#039;t obliterate a long message name.  Works with blocks and C-functions too.

19:24:18.099 -[MyApplctnAp.. application:didFinishLa..]@28   App initializing...
19:24:18.212 -[UserLibrary    getDeviceArtistsAndSongs]@118  querying user library
19:24:20.179 -[MyApplctnViewController        activate]@93   actually activating...
19:24:20.180 cFoo                                      @86   printing from C function
19:25:03.031 -[ScrollerController         addMagazine:]@85   addMagazine Tyler, The Creator
19:25:03.234 -[ScrollerController   pageTurnedFrom:to:]@201  0 -&gt; 0
19:27:39.703 __+[GUtil asyncImageFrom..]_block_invoke_1@59   restarting async image load
19:29:57.541 -[MusicPage            assembleAlbumView:]@121  image loaded


Enjoy!


///// ====== MyApplctn.h ======

#define DEBUG
#import &quot;LogUtils.h&quot;



///// ====== LogUtils.h ======
#import 

// ALog always displays output regardless of the DEBUG setting
#define ALog(fmt, ...) [LogUtils logString:[NSString stringWithFormat:fmt, ##__VA_ARGS__] fromMethod:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] atLine:__LINE__];

// DLog is almost a drop-in replacement for NSLog
// DLog();
// DLog(@&quot;here&quot;);
// DLog(@&quot;value: %d&quot;, x);
// Unfortunately this doesn&#039;t work DLog(aStringVariable); you have to do this instead DLog(@&quot;%@&quot;, aStringVariable);
#ifdef DEBUG
#   define DLog(fmt, ...) ALog(fmt, ##__VA_ARGS__)
#else
#	define DLog(...)
#endif


@interface LogUtils : NSObject

+ (void)logString:(NSString *)str fromMethod:(NSString *)method atLine:(int)line;

+ (NSString *)forceString:(NSString *)str toLength:(int)chars;

@end


//// ====== LogUtils.m ======

#import &quot;LogUtils.h&quot;

@implementation LogUtils

static NSDateFormatter *dateFormatter;

+ (void)logString:(NSString *)str fromMethod:(NSString *)method atLine:(int)line {
    
    if(dateFormatter == nil) {
        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@&quot;HH:mm:ss.SSS&quot;];
    }
    NSString *time = [dateFormatter stringFromDate:[NSDate date]];
    
    
    int METHOD_LENGTH = 42;
    NSRange openRange = [method rangeOfString:@&quot;[&quot;];
    NSRange closeRange = [method rangeOfString:@&quot;]&quot;];
    
    if(openRange.location == NSNotFound &#124;&#124; closeRange.location == NSNotFound) {
        method = [LogUtils forceString:method toLength:METHOD_LENGTH];
    } else {
        // looks like it&#039;s an Objective-C method
        // get fancy and abridge both the class and the message separately
        
        NSString *prefix = [method substringToIndex:openRange.location+1];
        NSString *meat = [method substringWithRange:NSMakeRange(openRange.location+1, closeRange.location - (openRange.location+1))];
        NSString *suffix = [method substringFromIndex:closeRange.location];
        
        float classToMessageRatio = .5;
        int N = METHOD_LENGTH - prefix.length - suffix.length;
        NSString *dots = @&quot;..&quot;;
        
        NSRange spaceRange = [meat rangeOfString:@&quot; &quot;];
        NSString *class = [meat substringToIndex:spaceRange.location];
        NSString *message = [meat substringFromIndex:spaceRange.location];
        
        if(meat.length &lt;= N) {
            while(class.length + message.length  N; n--) {
                float curRatio = (float)classLength / messageLength;
                if(curRatio &lt; classToMessageRatio) {
                    messageLength--;
                } else {
                    classLength--;
                }
            }
            
            if(classLength != class.length) {
                int k = classLength - dots.length;
                class = [[class substringToIndex:k] stringByAppendingString:dots];
            }
            
            if(messageLength != message.length) {
                int k = messageLength - dots.length;
                message = [[message substringToIndex:k] stringByAppendingString:dots];
            }
        }
        
        method = [NSString stringWithFormat:@&quot;%@%@%@%@&quot;, prefix, class, message, suffix];
    }
    
    NSString *lineString = [LogUtils forceString:[NSString stringWithFormat:@&quot;%d&quot;, line] toLength:4];
    
    NSString *output = [NSString stringWithFormat:@&quot;%@ %@@%@ %@&quot;, time, method, lineString, str];
    printf(&quot;%s\n&quot;, [output cStringUsingEncoding:NSUTF8StringEncoding]);
}


+ (NSString *)forceString:(NSString *)str toLength:(int)chars {
    if(str.length &lt;= chars) {
        while(str.length &lt; chars)
            str = [str stringByAppendingString:@&quot; &quot;];
        return str;
    }
    
    NSString *dots = @&quot;...&quot;;
    
    if(str.length &lt;= dots.length)
        return [dots substringToIndex:str.length];
    
    return [[str substringToIndex:chars - dots.length] stringByAppendingString:dots];
}

@end</description>
		<content:encoded><![CDATA[<p>Great help, thank your for the blog post!  I&#8217;m a bit of a perfectionist so here&#8217;s the DLog that works for me.  It prepends your output with a fixed-length string consisting of the Time, Function, and Line.  For my purposes (a UI-heavy iOS client) these are the most relevant pieces of data.</p>
<p>Here&#8217;s some sample output &#8212; it looks much nicer in monospace.  Notice that the class name and message name are treated as separate strings, so a long class name won&#8217;t obliterate a long message name.  Works with blocks and C-functions too.</p>
<p>19:24:18.099 -[MyApplctnAp.. application:didFinishLa..]@28   App initializing&#8230;<br />
19:24:18.212 -[UserLibrary    getDeviceArtistsAndSongs]@118  querying user library<br />
19:24:20.179 -[MyApplctnViewController        activate]@93   actually activating&#8230;<br />
19:24:20.180 cFoo                                      @86   printing from C function<br />
19:25:03.031 -[ScrollerController         addMagazine:]@85   addMagazine Tyler, The Creator<br />
19:25:03.234 -[ScrollerController   pageTurnedFrom:to:]@201  0 -> 0<br />
19:27:39.703 __+[GUtil asyncImageFrom..]_block_invoke_1@59   restarting async image load<br />
19:29:57.541 -[MusicPage            assembleAlbumView:]@121  image loaded</p>
<p>Enjoy!</p>
<p>///// ====== MyApplctn.h ======</p>
<p>#define DEBUG<br />
#import &#8220;LogUtils.h&#8221;</p>
<p>///// ====== LogUtils.h ======<br />
#import </p>
<p>// ALog always displays output regardless of the DEBUG setting<br />
#define ALog(fmt, &#8230;) [LogUtils logString:[NSString stringWithFormat:fmt, ##__VA_ARGS__] fromMethod:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] atLine:__LINE__];</p>
<p>// DLog is almost a drop-in replacement for NSLog<br />
// DLog();<br />
// DLog(@&#8221;here&#8221;);<br />
// DLog(@&#8221;value: %d&#8221;, x);<br />
// Unfortunately this doesn&#8217;t work DLog(aStringVariable); you have to do this instead DLog(@&#8221;%@&#8221;, aStringVariable);<br />
#ifdef DEBUG<br />
#   define DLog(fmt, &#8230;) ALog(fmt, ##__VA_ARGS__)<br />
#else<br />
#	define DLog(&#8230;)<br />
#endif</p>
<p>@interface LogUtils : NSObject</p>
<p>+ (void)logString:(NSString *)str fromMethod:(NSString *)method atLine:(int)line;</p>
<p>+ (NSString *)forceString:(NSString *)str toLength:(int)chars;</p>
<p>@end</p>
<p>//// ====== LogUtils.m ======</p>
<p>#import &#8220;LogUtils.h&#8221;</p>
<p>@implementation LogUtils</p>
<p>static NSDateFormatter *dateFormatter;</p>
<p>+ (void)logString:(NSString *)str fromMethod:(NSString *)method atLine:(int)line {</p>
<p>    if(dateFormatter == nil) {<br />
        dateFormatter = [[NSDateFormatter alloc] init];<br />
        [dateFormatter setDateFormat:@"HH:mm:ss.SSS"];<br />
    }<br />
    NSString *time = [dateFormatter stringFromDate:[NSDate date]];</p>
<p>    int METHOD_LENGTH = 42;<br />
    NSRange openRange = [method rangeOfString:@"["];<br />
    NSRange closeRange = [method rangeOfString:@"]&#8220;];</p>
<p>    if(openRange.location == NSNotFound || closeRange.location == NSNotFound) {<br />
        method = [LogUtils forceString:method toLength:METHOD_LENGTH];<br />
    } else {<br />
        // looks like it&#8217;s an Objective-C method<br />
        // get fancy and abridge both the class and the message separately</p>
<p>        NSString *prefix = [method substringToIndex:openRange.location+1];<br />
        NSString *meat = [method substringWithRange:NSMakeRange(openRange.location+1, closeRange.location - (openRange.location+1))];<br />
        NSString *suffix = [method substringFromIndex:closeRange.location];</p>
<p>        float classToMessageRatio = .5;<br />
        int N = METHOD_LENGTH &#8211; prefix.length &#8211; suffix.length;<br />
        NSString *dots = @&#8221;..&#8221;;</p>
<p>        NSRange spaceRange = [meat rangeOfString:@" "];<br />
        NSString *class = [meat substringToIndex:spaceRange.location];<br />
        NSString *message = [meat substringFromIndex:spaceRange.location];</p>
<p>        if(meat.length <= N) {<br />
            while(class.length + message.length  N; n&#8211;) {<br />
                float curRatio = (float)classLength / messageLength;<br />
                if(curRatio < classToMessageRatio) {<br />
                    messageLength&#8211;;<br />
                } else {<br />
                    classLength&#8211;;<br />
                }<br />
            }</p>
<p>            if(classLength != class.length) {<br />
                int k = classLength &#8211; dots.length;<br />
                class = [[class substringToIndex:k] stringByAppendingString:dots];<br />
            }</p>
<p>            if(messageLength != message.length) {<br />
                int k = messageLength &#8211; dots.length;<br />
                message = [[message substringToIndex:k] stringByAppendingString:dots];<br />
            }<br />
        }</p>
<p>        method = [NSString stringWithFormat:@"%@%@%@%@", prefix, class, message, suffix];<br />
    }</p>
<p>    NSString *lineString = [LogUtils forceString:[NSString stringWithFormat:@"%d", line] toLength:4];</p>
<p>    NSString *output = [NSString stringWithFormat:@"%@ %@@%@ %@", time, method, lineString, str];<br />
    printf(&#8221;%s\n&#8221;, [output cStringUsingEncoding:NSUTF8StringEncoding]);<br />
}</p>
<p>+ (NSString *)forceString:(NSString *)str toLength:(int)chars {<br />
    if(str.length <= chars) {<br />
        while(str.length < chars)<br />
            str = [str stringByAppendingString:@" "];<br />
        return str;<br />
    }</p>
<p>    NSString *dots = @&#8221;&#8230;&#8221;;</p>
<p>    if(str.length <= dots.length)<br />
        return [dots substringToIndex:str.length];</p>
<p>    return [[str substringToIndex:chars - dots.length] stringByAppendingString:dots];<br />
}</p>
<p>@end</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: numist</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-13102</link>
		<dc:creator>numist</dc:creator>
		<pubDate>Mon, 08 Aug 2011 02:38:57 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-13102</guid>
		<description>With regards to your &#039;// Unfortunately this doesn&#039;t work DLog(aStringVariable); you have to do this instead DLog(@&quot;%@&quot;, aStringVariable);&#039;, this can be fixed by dynamically creating an NSString in the macro to hold the user&#039;s format and arguments, like so:

#	define DLog(fmt, ...) NSLog((@&quot;%s [Line %d] %@&quot;), __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:(fmt), ##__VA_ARGS__]);

hope this helps.</description>
		<content:encoded><![CDATA[<p>With regards to your &#8216;// Unfortunately this doesn&#8217;t work DLog(aStringVariable); you have to do this instead DLog(@&#8221;%@&#8221;, aStringVariable);&#8217;, this can be fixed by dynamically creating an NSString in the macro to hold the user&#8217;s format and arguments, like so:</p>
<p>#	define DLog(fmt, &#8230;) NSLog((@&#8221;%s [Line %d] %@&#8221;), __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:(fmt), ##__VA_ARGS__]);</p>
<p>hope this helps.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tom</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-3573</link>
		<dc:creator>Tom</dc:creator>
		<pubDate>Tue, 29 Jun 2010 03:25:56 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-3573</guid>
		<description>And another thought -- if you add the DLog definition code and then do a global find/replace for NSLog/DLog, you will end up changing the code in the pch file as well.  

(Obvious, I know, but this gets me every time -- and it takes me several minutes to figure out why the code won&#039;t compile)</description>
		<content:encoded><![CDATA[<p>And another thought &#8212; if you add the DLog definition code and then do a global find/replace for NSLog/DLog, you will end up changing the code in the pch file as well.  </p>
<p>(Obvious, I know, but this gets me every time &#8212; and it takes me several minutes to figure out why the code won&#8217;t compile)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tom</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-3572</link>
		<dc:creator>Tom</dc:creator>
		<pubDate>Tue, 29 Jun 2010 03:23:42 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-3572</guid>
		<description>@Donna You can also edit the (several) template pch files located in 
/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application//[iPhone&#124;iPad] Application/___PROJECTNAMEASIDENTIFIER____Prefix.pch 

and add the DLog definition code.   Remember that its always a good idea to back up any template files before you start modifying them :-)</description>
		<content:encoded><![CDATA[<p>@Donna You can also edit the (several) template pch files located in<br />
/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application//[iPhone|iPad] Application/___PROJECTNAMEASIDENTIFIER____Prefix.pch </p>
<p>and add the DLog definition code.   Remember that its always a good idea to back up any template files before you start modifying them <img src='http://iPhoneIncubator.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nick</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-2989</link>
		<dc:creator>Nick</dc:creator>
		<pubDate>Thu, 06 May 2010 22:07:04 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-2989</guid>
		<description>@Donna: Place the macro code in your Prefix.pch file in each project. This will automagically include it in all files in the project.</description>
		<content:encoded><![CDATA[<p>@Donna: Place the macro code in your Prefix.pch file in each project. This will automagically include it in all files in the project.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nick</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-2988</link>
		<dc:creator>Nick</dc:creator>
		<pubDate>Thu, 06 May 2010 22:05:48 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-2988</guid>
		<description>@Susan: You could define DLog() to be NSLog() and just use the DEBUG flag to enable/disable it, if you don&#039;t want the extra information provided by the DLog() macro. But I don&#039;t think you can suppress the timestamp.</description>
		<content:encoded><![CDATA[<p>@Susan: You could define DLog() to be NSLog() and just use the DEBUG flag to enable/disable it, if you don&#8217;t want the extra information provided by the DLog() macro. But I don&#8217;t think you can suppress the timestamp.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Donna</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-2940</link>
		<dc:creator>Donna</dc:creator>
		<pubDate>Mon, 03 May 2010 02:32:20 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-2940</guid>
		<description>Where would be a good place to put all that #Define code?
And how would I include it in *EVERY* file in *ALL* my apps?</description>
		<content:encoded><![CDATA[<p>Where would be a good place to put all that #Define code?<br />
And how would I include it in *EVERY* file in *ALL* my apps?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Susan</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-2938</link>
		<dc:creator>Susan</dc:creator>
		<pubDate>Sun, 02 May 2010 14:33:20 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-2938</guid>
		<description>What if I needed DLog() to *NOT* show all that wasted info about the exact date/time/second... 100s of times?</description>
		<content:encoded><![CDATA[<p>What if I needed DLog() to *NOT* show all that wasted info about the exact date/time/second&#8230; 100s of times?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nick</title>
		<link>http://iPhoneIncubator.com/blog/debugging/the-evolution-of-a-replacement-for-nslog/comment-page-1#comment-2559</link>
		<dc:creator>Nick</dc:creator>
		<pubDate>Mon, 29 Mar 2010 00:27:27 +0000</pubDate>
		<guid isPermaLink="false">http://iPhoneIncubator.com/blog/?p=127#comment-2559</guid>
		<description>@Glen: The way the #ifdef preprocessor command works is that it looks to see if the variable following #ifdef has been defined at all. If it has been defined, regardless of it&#039;s value, then the statements following #ifdef will be included in the compilation. So in your case where you defined DEBUG = 0, #ifdef found that DEBUG had been defined, and thus included the logging code that followed.

When you changed the code to #if DEBUG, the preprocessor now checks for the value of the DEBUG variable. When it&#039;s zero, the following statements are ignored and when it&#039;s anything but zero the following statements are included.

Both ways work equally well, and it&#039;s more a style issue or personal preference, which one you use.</description>
		<content:encoded><![CDATA[<p>@Glen: The way the #ifdef preprocessor command works is that it looks to see if the variable following #ifdef has been defined at all. If it has been defined, regardless of it&#8217;s value, then the statements following #ifdef will be included in the compilation. So in your case where you defined DEBUG = 0, #ifdef found that DEBUG had been defined, and thus included the logging code that followed.</p>
<p>When you changed the code to #if DEBUG, the preprocessor now checks for the value of the DEBUG variable. When it&#8217;s zero, the following statements are ignored and when it&#8217;s anything but zero the following statements are included.</p>
<p>Both ways work equally well, and it&#8217;s more a style issue or personal preference, which one you use.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 4/16 queries in 0.079 seconds using disk: basic
Object Caching 360/366 objects using disk: basic

Served from: iphoneincubator.com @ 2012-02-08 01:45:12 -->
