Update on 2013-10-22: I’ve slightly updated the class for the latest CocoaLumberjack. Also, you can check out a sample project that uses this class here: https://github.com/pluton8/TextViewLoggerSample.
CocoaLumberjack is a nice library for logging on iOS, with many more features than the standard NSLog method, and allowing to customize logging to your needs. It’s not always convenient/possible to run your iOS app from Xcode to check the app’s logs, so I’ve created a simple logger that prints the messages to a UITextView UI component.
//// UITextViewLogger.h//// Created by Eugene Nikolsky on 8/8/12.// Copyright (c) 2012–2013. All rights reserved.//#import "DDLog.h"/* * A logger for CocoaLumberjack that outputs the messages to * a UITextView. * * If textView is not set up, the logs will be cached and then * flushed when it's set up. */@interfaceUITextViewLogger : DDAbstractLogger<DDLogger>// Text view where to print logs to.@property(nonatomic,weak)UITextView*textView;// Specifies if the text view should be automatically scrolled// to bottom after appending any log message.@property(nonatomic,assign)BOOLautoScrollsToBottom;@end
//// UITextViewLogger.m//// Created by Eugene Nikolsky on 8/8/12.// Copyright (c) 2012–2013. All rights reserved.//#import "UITextViewLogger.h"@interfaceUITextViewLogger()@property(nonatomic,strong)NSMutableArray*logMsgCache;@end@implementationUITextViewLogger@synthesizetextView=_textView;@synthesizeautoScrollsToBottom=_autoScrollsToBottom;@synthesizelogMsgCache=_logMsgCache;#pragma mark - Init-(id)init{if(self=[superinit]){_autoScrollsToBottom=YES;}returnself;}#pragma mark - Private Stuff-(void)appendTextViewString:(NSString*)string{NSAssert(self.textView!=nil,@"self.textView is nil");dispatch_async(dispatch_get_main_queue(),^(void){NSString*newText=[self.textView.textstringByAppendingString:string];self.textView.text=newText;if(self.autoScrollsToBottom){[self.textViewscrollRangeToVisible:NSMakeRange(newText.length,0)];}});}#pragma mark - DDLogger-(void)logMessage:(DDLogMessage*)logMessage{NSString*logMsg=logMessage->logMsg;if(formatter){logMsg=[formatterformatLogMessage:formatter];}if(logMsg){/* if textView is available, write to it, otherwise cache it */if(self.textView){[selfappendTextViewString:[NSStringstringWithFormat:@"\n%@",logMsg]];}else{if(!self.logMsgCache){self.logMsgCache=[NSMutableArrayarray];}[self.logMsgCacheaddObject:logMsg];}}}#pragma mark - Getters & Setters-(void)setTextView:(UITextView*)textView{if(_textView!=textView){_textView=textView;NSString*entireLog=[self.logMsgCachecomponentsJoinedByString:@"\n"];[self.logMsgCacheremoveAllObjects];[selfappendTextViewString:entireLog];}}@end
// import the file#import "UITextViewLogger.h"// …-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{// create the loggerUITextViewLogger*textViewLogger=[[[UITextViewLoggeralloc]init]autorelease];textViewLogger.autoScrollsToBottom=YES;[DDLogaddLogger:textViewLogger];// get your view controllerself.viewController=[[[ViewControlleralloc]initWithNibName:@"ViewController"bundle:nil]autorelease];// set up the text view for loggingtextViewLogger.textView=self.viewController.textViewLog;// …}
With this we get a chance to watch the logs in the app in realtime. Of course, you can easily attach a DDFileLogger to dump the messages to a file as well.
Important: if the app generates a great deal of logs, the logger will significantly reduce the performance, especially when the autoScrollsToBottom flag is set.