Related
I am trying to find a way for Cocoa Lumberjack to show me file and line number.
After looking through the docs and some Googling, I found no easy way to do this.
Is there any way to do this without adding custom formatter?
Well, like I said, there is no built-in way. So, I've implemented custom formatter:
#interface LineNumberLogFormatter : NSObject<DDLogFormatter>
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
#end
#implementation LineNumberLogFormatter
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage
{
NSString *path = [NSString stringWithCString:logMessage->file encoding:NSASCIIStringEncoding];
NSString *fileName = [path lastPathComponent];
return [NSString stringWithFormat:#"%#:%d %#", fileName, logMessage->lineNumber, logMessage->logMsg];
}
#end
While a separate formatter class would work, it would make your logging code a bit more verbose. In my project I opted for adding some additional macros that make use of CocoaLumberjack like so:
// Prefix.pch file
// ...
#ifdef DEBUG
#define DLogError(fmt, ...) DDLogError((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogWarn(fmt, ...) DDLogWarn((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogInfo(fmt, ...) DDLogInfo((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogDebug(fmt, ...) DDLogDebug((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogVerbose(fmt, ...) DDLogVerbose((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define DLogError(fmt, ...)
#define DLogWarn(fmt, ...)
#define DLogInfo(fmt, ...)
#define DLogDebug(fmt, ...)
#define DLogVerbose(fmt, ...)
#endif
In your client code, you could then call:
DLogWarn(#"This is a warning");
As UrK suggested, there isn't any trivial way, but it's pretty simple if you define your own formatter (see doc)
I've been through Introduction to Exception Programming Topics for Cocoa. Under Throwing Exceptions, there is one exception name shown: FileNotFoundException:
NSException *e = [NSException
exceptionWithName:#"FileNotFoundException"
reason:#"File Not Found on System"
userInfo:nil];
#throw e;
However, the Predefined Exceptions page lists about 10 exceptions and FileNotFoundException is not listed.
Where can I find a list of common or expected exceptions and names?
That's weird, these are the only constants defined in NSExcpetion.h that I see:
FOUNDATION_EXPORT NSString * const NSGenericException;
FOUNDATION_EXPORT NSString * const NSRangeException;
FOUNDATION_EXPORT NSString * const NSInvalidArgumentException;
FOUNDATION_EXPORT NSString * const NSInternalInconsistencyException;
FOUNDATION_EXPORT NSString * const NSMallocException;
FOUNDATION_EXPORT NSString * const NSObjectInaccessibleException;
FOUNDATION_EXPORT NSString * const NSObjectNotAvailableException;
FOUNDATION_EXPORT NSString * const NSDestinationInvalidException;
FOUNDATION_EXPORT NSString * const NSPortTimeoutException;
FOUNDATION_EXPORT NSString * const NSInvalidSendPortException;
FOUNDATION_EXPORT NSString * const NSInvalidReceivePortException;
FOUNDATION_EXPORT NSString * const NSPortSendException;
FOUNDATION_EXPORT NSString * const NSPortReceiveException;
FOUNDATION_EXPORT NSString * const NSOldStyleException;
The exception FileNotFoundException shown in that particular example is not a predefined exception. All predefined exceptions begin with prefix NS, like NSRangeException etc. Hence you cannot see it listed under the predefined list of exceptions.
From Apple docs
Note that all predefined exceptions begin with the prefix "NS", so you should avoid using the same prefix when creating new exception names.
FileNotFoundException is custom exception, which needs to be raised and handled by the developer for custom error conditions. It is recommended that all custom exception should avoid using the prefix NS.
As mentioned by pfrank in his answer, list of predefined exceptions can be found here
extern NSString *NSGenericException;
extern NSString *NSRangeException;
extern NSString *NSInvalidArgumentException;
extern NSString *NSInternalInconsistencyException;
extern NSString *NSMallocException;
extern NSString *NSObjectInaccessibleException;
extern NSString *NSObjectNotAvailableException;
extern NSString *NSDestinationInvalidException;
extern NSString *NSPortTimeoutException;
extern NSString *NSInvalidSendPortException;
extern NSString *NSInvalidReceivePortException;
extern NSString *NSPortSendException;
extern NSString *NSPortReceiveException;
extern NSString *NSOldStyleException;
Hope that helps!
Is there a way to use SQLite soundex() in iOS apps?
Please guide me to find a way...
Tried Homegrew but it works on terminal and I need to run soundex everytime in terminal. Also i dont know how to port to iOS APP.
Terminal work
You can the sqlite3_create_function to create the soundex SQL function:
#import "ViewController.h"
#import <sqlite3.h>
void soundex(sqlite3_context *context, int argc, sqlite3_value **argv);
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self test];
}
- (sqlite3 *)openDatabase
{
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *path = [docsPath stringByAppendingPathComponent:#"test.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path])
{
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"db"];
[fileManager copyItemAtPath:bundlePath toPath:path error:nil];
}
sqlite3 *db;
int rc;
if ((rc = sqlite3_open_v2([path UTF8String], &db, SQLITE_OPEN_READWRITE, NULL)) != SQLITE_OK)
{
NSLog(#"%s: sqlite3_open_v2 failed: %d", __FUNCTION__, rc);
}
return db;
}
- (BOOL)createFunction:(sqlite3 *)db
{
int rc;
if ((rc = sqlite3_create_function(db, "soundex", 1, SQLITE_ANY, NULL, soundex, NULL, NULL)) != SQLITE_OK)
{
NSLog(#"%s: sqlite3_create_function error: %s", __FUNCTION__, sqlite3_errmsg(db));
}
return rc;
}
- (void)test
{
int rc;
sqlite3 *db = [self openDatabase];
[self createFunction:db];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, "SELECT name FROM todo WHERE soundex(name) = soundex('Mani')", -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"%s: sqlite3_prepare_v2 error: %s", __FUNCTION__, sqlite3_errmsg(db));
}
while ((rc = sqlite3_step(statement)) == SQLITE_ROW)
{
const unsigned char *name = sqlite3_column_text(statement, 0);
if (name)
NSLog(#"name=%s", name);
else
NSLog(#"name=NULL");
}
if (rc != SQLITE_DONE)
{
NSLog(#"%s: sqlite3_step error: %s", __FUNCTION__, sqlite3_errmsg(db));
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
#end
void soundex(sqlite3_context *context, int argc, sqlite3_value **argv)
{
const char *str = (const char*)sqlite3_value_text(argv[0]);
const char *in = str;
static int code[] =
{ 0,1,2,3,0,1,2,0,0,2,2,4,5,5,0,1,2,6,2,3,0,1,0,2,0,2 };
/* a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z */
char ch;
int last;
int count;
char key[5];
/* Set up default key, complete with trailing '0's */
strcpy(key, "Z000");
/* Advance to the first letter. If none present,
return default key */
while (*in != '\0' && !isalpha(*in))
++in;
if (*in == '\0') {
sqlite3_result_text(context, key, 4, SQLITE_TRANSIENT);
return;
}
/* Pull out the first letter, uppercase it, and
set up for main loop */
key[0] = toupper(*in);
last = code[key[0] - 'A'];
++in;
/* Scan rest of string, stop at end of string or
when the key is full */
for (count = 1; count < 4 && *in != '\0'; ++in) {
/* If non-alpha, ignore the character altogether */
if (isalpha(*in)) {
ch = tolower(*in);
/* Fold together adjacent letters sharing the same code */
if (last != code[ch - 'a']) {
last = code[ch - 'a'];
/* Ignore code==0 letters except as separators */
if (last != 0)
key[count++] = '0' + last;
}
}
}
sqlite3_result_text(context, key, 4, SQLITE_TRANSIENT);
}
You need to include the sqlite.c/sqlite.h files in your project from the sqlite amalgamation itself vs. using the libsqlite dylib.
Be sure to set the SQLITE_SOUNDEX preprocessor flag as well to include this feature when you build.
1) download and unzip the sqlite amalgamation. Add the sqlite.h/sqlite.c files to your project.
2) add SQLITE_SOUNDEX=1 to your project's Preprocessor Macros, via the Build Settings screen in XCode.
3) remove libsqlite3XXX.dylib from your project's Link With Libraries list, via the Build Phases screen in Xcode.
Hello guys I have found this code that is used to create a different NSLog (without data and timestamps) that displays the class where the log was made and the line number.
I have read that is possible to disable the logging only for certain classes with NO_LOG but there was not explained how to use it exactly, I am quite new to obj-c and I appreciate an explanation on how to disable logging for certain classes and how to activate and deactivate the debugging. thanks
#define MAKESTRING(__VA_ARGS__) #__VA_ARGS__
#define TOSTRING(...) MAKESTRING(__VA_ARGS__)
static inline void PxReportv(BOOL doLog, char const *file, int line, NSString *prefix, NSString *fmt, va_list argList) {
if (doLog) {
NSString *fileNameWithExtension = [[NSString stringWithFormat:#"%s", file] lastPathComponent];
#ifdef NO_LOG
NSString *fileName = [fileNameWithExtension stringByDeletingPathExtension];
char *f = TOSTRING(NO_LOG);
NSArray *comps = [[[NSString alloc] initWithFormat:#"%s", f] componentsSeparatedByString:#","];
for (NSString *except in comps) {
if ([except isEqualToString:fileName]) {
return;
}
}
#endif
vprintf([[[NSString alloc] initWithFormat:[[NSString alloc] initWithFormat:#"%# <%# [%d]> %#\n", prefix, fileNameWithExtension, line, fmt] arguments:argList] cStringUsingEncoding:NSUTF8StringEncoding], NULL);
}
}
static inline void PxReport(BOOL doLog, char const *file, int line, NSString *prefix, NSString *fmt, ...) {
va_list ap;
va_start(ap, fmt);
PxReportv(doLog, file, line, prefix, fmt, ap);
va_end(ap);
}
#define PxError(...) PxReport(YES, __FILE__, __LINE__, #"[ERROR]", __VA_ARGS__)
#ifdef DEBUG
#define PxDebug(...) PxReport(YES, __FILE__, __LINE__, #"[DEBUG]", __VA_ARGS__)
#define NSLog(...) PxReport(YES, __FILE__, __LINE__, #"", __VA_ARGS__)
#else
#define PxDebug(...)
#define NSLog(...)
#endif
Add this:
#define NO_LOG 1
before #importing the file you've shown above.
BTW a better implementation would define PxDebug() and NSLog() to nothing if NO_LOG was defined...
that is quite a verbose solution, i made one that is a lot neater than that
#ifndef DebugLog_h
#define DebugLog_h
#if DEBUG
#define DLog(...) do{\
printf("[%s:%d]", __FUNCTION__, __LINE__);\
NSString *_S_ = [NSString stringWithFormat:__VA_ARGS__];\
printf(" %s\n",[_S_ cStringUsingEncoding:NSUTF8StringEncoding]);\
}while(0);
#else
#define DLog(...)
#endif
#endif
that will print the line number, class and function it came from
eg:
Dlog(#"hello %d", 123);
[-[SomeViewController viewWillAppear:]:91] hello 123
edit: if you add the file to your projectname-Prefix.pch file, then you can use it without having to include it everywhere
and it will automatically be taken out of release builds, because DEBUG is defined as a project definition automatically when its in debug mode
I use it to check iOS version, but it doesn't work:
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_5_0
#define kCFCoreFoundationVersionNumber_iPhoneOS_5_0 675.000000
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
#define IF_IOS5_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_5_0) \
{ \
__VA_ARGS__ \
}
#else
#define IF_IOS5_OR_GREATER 0
#endif
when I make
#if IF_IOS5_OR_GREATER
NSLog(#"iOS5");
#endif
nothing happens. Is something wrong here?
Much simpler:
#define IS_IOS6_AND_UP ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0)
#ifdef __IPHONE_5_0
etc
Just look for that constant. All the objective c constants start with two underscores
You've defined a macro, but you're using it in the non-macro way. Try something like this, with your same macro definition.
IF_IOS5_OR_GREATER(NSLog(#"iOS5");)
(This is instead of your #if/#endif block.)
Define this method:
+(BOOL)iOS_5 {
NSString *osVersion = #"5.0";
NSString *currOsVersion = [[UIDevice currentDevice] systemVersion];
return [currOsVersion compare:osVersion options:NSNumericSearch] == NSOrderedAscending;
}
Then define the macro as that method.
For a runtime check use something like this:
- (BOOL)iOSVersionIsAtLeast:(NSString*)version {
NSComparisonResult result = [[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch];
return (result == NSOrderedDescending || result == NSOrderedSame);
}
If you create a category on UIDevice for it, you can use it as such:
#implementation UIDevice (OSVersion)
- (BOOL)iOSVersionIsAtLeast:(NSString*)version {
NSComparisonResult result = [[self systemVersion] compare:version options:NSNumericSearch];
return (result == NSOrderedDescending || result == NSOrderedSame);
}
#end
...
if([[UIDevice currentDevice] iOSVersionIsAtLeast:#"6.0"]) self.navigationBar.shadowImage = [UIImage new];
#define isIOS7 ([[[UIDevice currentDevice]systemVersion]floatValue] > 6.9) ?1 :0