Change macro value from .m file - objective-c

I have defined a macro value in Constant.h (#define OK "OK")
And I imported in a First.m file and redefined it (#undef OK, #define OK "Hi")
Then I include Constant.h in Second.m and when I access the "OK" the value is still "OK" not "Hi"
I noticed that the value only changed in First.m.
Just wondering how to change the OK value globally.
Since many .m file are acessing the OK and OK needs to be changed often according to different event
Thanks

#define OK(str) ISVALIDBOOL(str) ? #"HI" : #"OK"
#define ISVALIDBOOL(str) (str == NO) // Import in above header
BOOL str=YES;
NSLog(#"Hi:%#",OK(str));
str=NO;
NSLog(#"Ok:%#",OK(str));
No other way to change the macro at runtime
Refer that

You'll need to turn the OK macro from a simple string definition into some conditional statement that tests this special event you talk about. You can only change a macro in the implementation file being compiled; changes are not seen in other compilation units. So the change must be made to the macro in the header file itself.
For example, if the two strings are based on the success of an operation you could do:
#define OK(condition) ((condition) ? #"OK" : #"Failed")
and use it like this:
BOOL success = [self doThing];
NSLog(#"doThing %#", OK(success));
I often define a similar macro to turn BOOLs into NSStrings:
#define STRBOOL(b) ((b) ? #"YES" : #"NO"))

Related

IntelliJ Velocity template $Character.isUpperCase return false on uppercase char

I'm trying to make a setter template which will allow me to use a m prefix for member variables. So when I have a field mTest is should give me a setter: public setTest and not setmTest. I think I have the correct logic, but Character.isUpperCase returns false even if it's a upper case letter. I've added some debugging a bit improvised, since it's kind of weird to test, because IntelliJ check if there is a proper function returned. When generating a setter I get an error dialog where I can see my output of:
#if($Character.isUpperCase($paramName.charAt(1)))
paramIsUppercase: $paramName.charAt(1)
#else
paramIsNotUppercase: $paramName.charAt(1)
#end
Complete code:
#set($paramName = $helper.getParamName($field, $project))
// debugging
#if($Character.isUpperCase($paramName.charAt(1)))
paramIsUppercase: $paramName.charAt(1)
#else
paramIsNotUppercase: $paramName.charAt(1)
#end
#if($StringUtil.startsWith($paramName, 'm') && $Character.isUpperCase($paramName.charAt(1)))
#set($paramName = $paramName.substring(1))
#end
#set($paramName = $StringUtil.decapitalize($paramName))
public ##
#if($field.modifierStatic)
static void ##
#else
$classname ##
#end
set$StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($paramName))($field.type $paramName) {
#if ($field.name == $paramName)
#if (!$field.modifierStatic)
this.##
#else
$classname.##
#end
#end
$field.name = $paramName;
#if(!$field.modifierStatic)
return this;
#end
}
When using this to create a setter for mTest I get an error for my debugging
paramIsNotUppercase: T
Why is this returning false and is there a fix for this?
It looks like the problem is that $Character is not defined, which means the expression will always return false. There is a way to get around this. It is a horrible hack, but it works for me. Use the following template lines.
## get some object
#set($String='')
## abuse it to obtain the desired jdk class
#set($Character=$String.class.forName('java.lang.Character'))
After that you can use $Character regularly as you desire (i.e. $Character.isUpperCase($paramName.charAt(1))).
However there is no need to create your own setter template if you want to use prefixes for fields. Just go to the settings File | Settings | Editor | Code Style | Java | Code Generation and specify a Name prefix for Field and getters and setters will be generated correctly.

Objective C - Defining macro to call a method?

I want to define a macro to call the following, Is this possible?
I also want it to accept format string.
- (void)logString:(NSString *)string withLogLogLevel:(LogLevel)logLevel
{
// Sav log to file
}
DLog("text");
[Logger logString:text withLogLevel:LogLevelDebug];
ILog("text");
[Logger logString:text withLogLevel:LogLevelInfo];
ELog("text");
[Logger logString:text withLogLevel:LogLevelInfo];
Assuming that logString:withLogLevel: takes a single string parameter in addition to the log level, this should be possible:
#define DLog(x) [Logger logString:(x) withLogLevel:LogLevelDebug]
Note the parentheses around the macro parameter, it is useful when macros are called with composite expressions.
Assuming that the logger takes NSString objects, not C string, you should use the macro like this:
DLog(#"Text");
However, in this case it is not clear why would one prefer a macro to a simple function call:
void DLog(NSString *str) {
[Logger logString:str withLogLevel:LogLevelDebug];
}

Standards for comments in NSLocalizedString

How do people write their comments for their NSLocalizedStrings? Is there a standard guideline that we should follow? For example if I have:
NSLocalizedString(#"Tap your account to sign in", #"");
and my comment is "Text that asks user to sign in by tapping on the account", is this a bit ambigous? Should I leave the comment out if it's pretty much self-explanatory?
Another question is, what if I have a bunch of ProgressHUD that has a text set to LoggingIn, what would be an easy way to sync across my app project that this needs to be localized into NSLocalizedString (#"Logging In", #"some description"); Is there a tool for performing such tasks?
The second parameter is a comment that will automatically appear in the strings file if you use the genstrings command-line utility, which can create the strings file for you by scanning your source code.
The comment is useful for your localizers. For example:
NSLocalizedString(#"Save",#"Title of the Save button in the theme saving dialog");
When you run genstrings, this will produce an entry in the Localizable.strings file like this:
/* Title of the Save button in the theme saving dialog */
"Save" = "Save";
In your specific example, it's fairly obvious what the comment means, but not the context. You should probably add some context like so:
NSLocalizedString(#"Tap your account to sign in", #"Instruct user to tap their account to sign in (Facebook account, main game preferences)");
That way the localizer knows exactly what button you're referring to.
This becomes even more important for buttons labelled "Share" or some other non-specific label:
NSLocalizedString(#"Share", #"Label for sharing button on main image editing screen");
(This is a modified version of my answer to this similar question).
Rob Keniger is right. I also would like to add this:
Second param can be used as .. default value!!
(NSLocalizedStringWithDefaultValue does not work properly with genstring, that's why I proposed this solution)
Here is my Custom implementation that use NSLocalizedString that use comment as default value:
1 . In your pre compiled header (.pch file) , redefine the 'NSLocalizedString' macro:
// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"
#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key comment:_comment]
2. create a class to implement the localization handler
#import "LocalizationHandlerUtil.h"
#implementation LocalizationHandlerUtil
static LocalizationHandlerUtil * singleton = nil;
+ (LocalizationHandlerUtil *)singleton
{
return singleton;
}
__attribute__((constructor))
static void staticInit_singleton()
{
singleton = [[LocalizationHandlerUtil alloc] init];
}
- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
// default localized string loading
NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];
// if (value == key) and comment is not nil -> returns comment
if([localizedString isEqualToString:key] && comment !=nil)
return comment;
return localizedString;
}
#end
3. Use it!
Make sure you add a Run script in your App Build Phases so you Localizable.strings file will be updated at each build, i.e., new localized string will be added in your Localized.strings file:
My build phase Script is a shell script:
Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder
So when you add this new line in your code:
self.title = NSLocalizedString(#"view_settings_title", #"Settings");
Then perform a build, your ./Localizable.scripts file will contain this new line:
/* Settings */
"view_settings_title" = "view_settings_title";
And since key == value for 'view_settings_title', the custom LocalizedStringHandler will returns the comment, i.e. 'Settings"
VoilĂ  :-)

C Callback in Objective-C (IOKIT)

I am trying to write some code that interacts with an USB device in Objective C, and I got stuck on setting the callback function for incoming reports. In my case it's an IOKIT function but I think the problem is more general as I (apparently) don't know how to correctly set a C callback function in Objective-C. I've got a Class "USBController" that handles the io functions
USBController.m:
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h>
#include <IOKit/hid/IOHIDLib.h>
#import "USBController.h"
static void Handle_IOHIDDeviceIOHIDReportCallback(
void * inContext, // context from IOHIDDeviceRegisterInputReportCallback
IOReturn inResult, // completion result for the input report operation
void * inSender, // IOHIDDeviceRef of the device this report is from
IOHIDReportType inType, // the report type
uint32_t inReportID, // the report ID
uint8_t * inReport, // pointer to the report data
CFIndex InReportLength) // the actual size of the input report
{
printf("hello"); //just to see if the function is called
}
#implementation USBController
- (void)ConnectToDevice {
...
IOHIDDeviceRegisterInputReportCallback(tIOHIDDeviceRefs[0], report, reportSize,
Handle_IOHIDDeviceIOHIDReportCallback,(void*)self);
...
}
...
#end
All the functions are also declared in the header file.
I think I did pretty much the same as what I've found here, but it doesn't work. The project compiles nicely and everything works up till the moment there is input and the callback function is to be called. Then I get an "EXC_BAD_ACCESS" error. The first three arguments of the function are correct. I'm not so sure about the context..
What did I do wrong?
I am not sure at all that your EXEC_BAD_ACCESS depends on your callback. Indeed, if you say that it is called (I suppose you see the log) and since it only logs a message, there should be no problem with this.
EXEC_BAD_ACCESS is caused by an attempt to access an already deallocated object. You can get more information in two ways:
execute the program in debug mode, so when it crashes you will be able to see the stack content;
activate NSZombies or run the program using the performance tool Zombies; this will tell you exactly which object was accessed after its deallocation.
I know how to fix this. When calling this:
IOHIDDeviceRegisterInputReportCallback(tIOHIDDeviceRefs[0], report, reportSize,
Handle_IOHIDDeviceIOHIDReportCallback,(void*)self);
You don't include the code for the creation/type of the value called report. However the method name "Handle_IOHIDDeviceIOHIDReportCallback" comes from an Apple document where there is an error in the creation of the report value. https://developer.apple.com/library/archive/technotes/tn2187/_index.html
CFIndex reportSize = 64;
uint8_t report = malloc( reportSize ); // <---- WRONG
IOHIDDeviceRegisterInputReportCallback( deviceRef,
report,
reportSize,
Handle_IOHIDDeviceIOHIDReportCallback,
context );
Instead do this:
uint8_t *report = (uint8_t *)malloc(reportSize);

Velocity: Is a any way to check if variable is defined

I want to include one template nested into others cont1, cont2, cont3.
And nested template should be hide one specific control for cont1 only.
Before inclusion into cont1 I would like to assign value to some flag variable $hideMyControl.
And inside nested template I would like to check if $hideMyControl is assigned value.
How to perform such check?
#if($hideMyControl)
// your code
#end
If $hideMyControl is defined, your code will execute
You can do this using
#if($!{$articleLeader})
// Perform your operation or the template part you want to show.
#end
For more info, see the 'formal reference' section of the Apache Velocity Reference Manual.
#if($!{hideMyControl} != "")
## do something if $hideMyControl is defined
#end
This works for me in AWS API Gateway Body Mapping Templates. Please refer to Quiet Reference Notation in Velocity User Guide for more information.
I was using
#if ($hideMyControl)
//do something
#end
since a few months ago,
however today its not working anymore.
I came here to find help, and noticed a new way of writing it :
#if($!{$hideMyControl})
// do something
#end
this code works!
According to the docs for Strict Reference Mode it is possible to several constructions to check if variable is defined.
#if ($foo)#end ## False
#if ( ! $foo)#end ## True
#if ($foo && $foo.bar)#end ## False and $foo.bar will not be evaluated
#if ($foo && $foo == "bar")#end ## False and $foo == "bar" wil not be evaluated
#if ($foo1 || $foo2)#end ## False $foo1 and $foo2 are not defined
So this code works in my case.
#if( !$value )
// Perform your operation or the template part you want to show.
#end
To check if $hideMyControl is in Velocity context and IS NOT boolean 'true' value (or 'false' as well):
#if ($hideMyControl && $hideMyControl != true)
##do stuff
#end
Sure, if you really use your $hideMyControl variable as boolean type, you don't need second part of condition.