PFLoggingConsole is a development utility class that logs NSLog statements to the screen of a device. I find it very convenient for testing of communication between devices. I am using it while experimenting with the iOS Multipeer Connectivity framework. In this post I will explain what it does and how it works.
I have created a small project on Github that shows how to apply the PFLoggingConsole in a simple app (based on the Single View Application Template). You can download the sources associated with this post here.
When you run the app you will see the PFLoggingConsole screen:
The text on the console is produced by ordinary NSLog statements in the code.
Below is the PFLoggingConsole.h code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#define NSLog( s, ... ) [PFLoggingConsole log:[NSString stringWithFormat:@"> %@",[NSString stringWithFormat:(s), ##__VA_ARGS__]]] /** A singleton UITextView subclass that can be used as a logging console. By importing this file into another class file all NSLog calls of that class will log to this logging console. You typically add this logging console as a subview of the root viewcontroller view of your app, when debugging. */ @interface PFLoggingConsole : UITextView /** @return the singleton. If it was not yet created, it will be. */ + (PFLoggingConsole*) getInstance; /** Logs a line of text to the console. */ + (void)log:(NSString*) lineOfText; @end |
PFLoggingConsole is a singleton UITextView subclass. By importing this PFLoggingConsole.h into another class file all NSLog calls of that class will log to this logging console. This works because the #define replaces all NSLog statements by calls to the PFLoggingConsole singleton.
The implementation code PFLoggingConsole.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#import "PFLoggingConsole.h" @implementation PFLoggingConsole static PFLoggingConsole *theConsole = nil; #pragma mark - Public + (PFLoggingConsole*) getInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ theConsole = [[PFLoggingConsole alloc]init]; [theConsole setEditable:NO]; [theConsole setScrollEnabled:YES]; }); return theConsole; } + (void)log:(NSString*) lineOfText { // PFLoggingConsole is a UITextView subclass. // UIKit classes should be used only from an application’s main thread. // Since we have no idea from which thread this method is called we dispatch it to the main queue. // This way the logging always will work, even when called from another thread. dispatch_async(dispatch_get_main_queue(),^{ if (!theConsole) { [PFLoggingConsole getInstance]; } NSString *newText; // do not add a newline when the console is empty if (theConsole.text.length == 0) { newText = lineOfText; } else { newText = [NSString stringWithFormat:@"%@n%@", theConsole.text, lineOfText]; } [theConsole setText:newText]; [theConsole scrollRangeToVisible:NSMakeRange([theConsole.text length], 0)]; }); } @end |
So far the description of the PFLoggingConsole itself. The code snippet below is taken from the PFAppDelegate and shows the logic that presents the logging console to the user:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** Adds the logging console as a subview of the rootViewController view */ - (void) addLoggingConsole { PFLoggingConsole *loggingConsole = [PFLoggingConsole getInstance]; CGRect screenRect = [[UIScreen mainScreen] bounds]; CGFloat screenWidth = screenRect.size.width; CGFloat screenHeight = screenRect.size.height; loggingConsole.frame = CGRectMake(20, 30, screenWidth - 40, screenHeight - 50); loggingConsole.layer.borderWidth = 1.0; loggingConsole.layer.borderColor = [[UIColor blackColor] CGColor]; [self.window.rootViewController.view addSubview:loggingConsole]; } |
The method addLoggingConsole creates the PFLoggingConsole instance, adapts its size to the uiscreen size, and adds it as a subview of the root viewcontroller view of the app.
To use the logging console in your own project add PFLoggingConsole.h and PFLoggingConsole.m to your source code tree, create an instance and add it as a subview wherever you want it to be in the view hierarchy. You can take the method addLoggingConsole shown above as an example.