Offer the ability to enable/disable logging programmatically - objective-c

I'm building a .Framework and I would like to offer to the developers using my framework the ability to hide or show the NSLogs that are within the framework.
I already use this solution
Prefix.pch
#ifdef PY_LOGS
# define PYLog(...) NSLog(__VA_ARGS__)
#else
# define PYLog(...)
#endif
and then use PYLog() in my frameworks so that the developer can set the PY_LOGS flag or not in the preprocessor macros.
It works perfectly but I would like a solution that allows the developer to call something like
[[MyFramework sharedInstance] setDebug:YES];
Does anyone know how to do this?

Look at using a common solution like LibComponentLogging.

Whats wrong with?
#ifdef PY_LOGS
# define PYLog(...) if([[MyFramework sharedInstance] isLoggingEnabled]){ NSLog(__VA_ARGS__); }
#else
# define PYLog(...)
#endif
Objective-C messaging efficiency is the least of your worries.

Related

Swift Compiler Flags Wont affect Objective-C code

under Active Compilation Conditions i have added a new flag (for debug only) called SOMEFLAG.
the check is implemented like so and works great:
#if SOMEFLAG
print("SOMEFLAG is true");
#endif
it actually prints like i would expect. now, i need to examine the same flag from Objective-C class and it never evaluates to true. any idea why?
should i make this flag in other way?
in general my goal is to be able to detect when it is executed from another target, the build is triggered from the cli.
if there is other way that less limiting i would like to know.
thanks!
In Objective-C (and other C-like languages that use a preprocessor) the canonical way to check whether a symbol is defined would be using #ifdef, not #if. There is an #if directive in Objective-C, but it doesn't behave quite the same way as the Swift #if compiler directive.

Writing library code to support both ARC and MRR

I'm working on a library and I would like to support both memory management approaches (ARC and MRR) in one codebase.
I don't want to force users to use special flags for my code (-fobjc-arc).
I know about the preprocessor test: #if __has_feature(objc_arc), but what is the best practice to use that to cover the all differences?
Does anyone have any experience with that to make it clean and easy to work with?
The preferable way would be to use some macros for translations between ARC and non-ARC, which I can use in my code.
=========
My problem was solved by the accepted answer, but as a tip for others, I found a blog post by John Blanco giving the best set of examples for how to handle my problem.
Refer the code of MBProgressHUD in github. I think, that's what you want.
#if __has_feature(objc_arc)
#define MB_AUTORELEASE(exp) exp
#define MB_RELEASE(exp) exp
#define MB_RETAIN(exp) exp
#else
#define MB_AUTORELEASE(exp) [exp autorelease]
#define MB_RELEASE(exp) [exp release]
#define MB_RETAIN(exp) [exp retain]
#endif
This is how they are using these macros
self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]);
Either use ARC and instruct people who will use the code to set compilation flags per file (-fobjc-arc), and force them to do so by adding this to the header:
#if !__has_feature(objc_arc)
#error ARC must be enabled!
#endif
Or build as lib/framework with ARC enabled. Wrapping memory management code in preprocessor directives is a terrible idea.
One way to support both ARC and Non-ARC code is to go to the Target, Build Phases, and to the Compile Sources section.
From there you should see all your .m files. You can then add to any file -fno-objc-arc under the Compiler Flags to tell the compiler to ignore ARC.
Yeah, don't do this. You'll end up having to test your code fully twice for every change. And debugging everything twice. It isn't worth the effort.
You really really want to write your code purely ARC or purely non-ARC.
There are very few constructs that can appear in a header file that won't work in one or the other.

What design pattern should I use for building a cross OSX and iOS library?

I'm trying to build a library that has convenience methods for dealing with the iOS and OSX AddressBook frameworks (Contact List on iOS and Contacts on OSX) and includes such methods as:
(BOOL)addressBookContainsRecordWithID:(NSString *)recordID (NSInteger in the case of OSX)
(id)newOrExistingGroupWithName:(NSString *)groupName
(id)addressBookRecordWithID:(NSString *)recordID
etc.
And I'd like to be able to call these methods on both OSX and iOS, but have that method execute the logic path respective for each device. For example, on OSX it would use a method that uses ABPerson and ABGroup whereas on iOS it would use a method that uses ABRecordRef.
My current plan is to have preprocessor directives (#if device-is-osx callOSXMethod #else callIOSMethod) which figure out whether I'm using iOS or OSX and use the correct method.
Is there a better way I could go about this? I feel like there is some design patter that could be used here.
It depends on how much shared code there will be between your two different implementations. If almost all of the code is shared except for a few specific method calls to the AddressBook frameworks then preprocessor directives with #if TARGET_OS_IPHONE are the way to go.
On the other hand, if you find that the code in your #if blocks is getting quite long, it usually makes more sense to split the Mac and iOS implementations into separate files that share an identical interface. Thus you'd have:
MyAddressBook.h - Shared by both
MyAddressBook_Mac.h - Mac implementation of MyAddressBook
MyAddressBook_iOS.h - iOS implementation of MyAddressBook
This is made easier by the fact that your implementations can even have different instance variables by using a class extension inside each implementation file. This second pattern leads to greater readability at the cost of having to maintain whatever common code there is in two places.
Preprocessor directives are the way to go. There are even predefined ones you can use:
#if TARGET_OS_IPHONE
// iOS code here
#else
// OS X code here
#endif

How do i know what version of ObjC language am i using?

This is kind of a silly question, but really, how can i tell whether i am using ObjC version 2 or something else?
I can always assume "the latest", but i'd rather know :)
Is there a command line check i can run? Please advise
If you are running 10.5 or later, or any version of iOS, your computer is running Objective-C 2. If you are writing code which you want to work on systems before this, you can check for the __OBJC2__ macro, which will be defined only for Objective-C 2 and later systems.
#ifdef __OBJC2__
// use objective-c 2
#elif defined(__OBJC__)
// use objective-c 1
#else
// no objective-c
#endif

can i use DEBUG_NEW on managed code?

can i use:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
in managed code?
like c# or managed c++?
That should work in C++/CLI just as well as it does in standard C++, which is to say, it's officially not allowed to redefine keyword such as new, but most compilers will let you do it.
With __FILE__ there is no problem, although you probably want to store it in a managed string, if you want to use it from managed code.