#define macro does not take variable values - objective-c

I have created #define statement in project's pch file so it can be seen in all files in the project, the statement is: #define MYURL(x,y) #"http://internal-sps/providers.aspx?category=(a)&regionID=(y)"
however, I use this macro in any file inside the project like this:
NSString *url = MYURL(#"category1",#"3");
then NSLog(#"%#", url); the console shows this:
http://internal-sps/providers.aspx?category=(a)&regionID=(y) not the actual values.
how can i get the actual values for this macro ?

Change:
#define MYURL(x,y) #"http://internal-sps/providers.aspx?category=(a)&regionID=(y)"
to:
#define MYURL(x,y) "http://internal-sps/providers.aspx?category=(a)&regionID=("y")"
and use your macro like this:
NSString *url = #MYURL("category1","3");
Note: if that a is actually meant to be an x then it would be:
#define MYURL(x,y) "http://internal-sps/providers.aspx?category=("x")&regionID=("y")"

Related

Defining constant in objective-c

I'm pretty new to Objective C and I want to define some constant based on the value of the other constant.
#define MODE_DEV YES
#if (MODE_DEV)
#define WEBSERVICE_URL #"http://dev.testurl.com";
#else
#define WEBSERVICE_URL #"http://prod.testurl.com";
#endif
And I'm using WEBSERVICE_URL as following.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#add_device_token", WEBSERVICE_URL]];
But I'm getting error in the above line.
The error says, "Expected ]".
I have no idea what is wrong with my code.
The problem is the semicolon at the end of your #define lines.
Remember, a #define is just a textual substitution. So you are saying:
#define WEBSERVICE_URL #"http://dev.testurl.com";
Thus the semicolon is part of the text substitution and gives nonsense in context:
NSURL *url =
[NSURL URLWithString:
[NSString stringWithFormat:
#"%#add_device_token", #"http://dev.testurl.com";]];
^
The key you should remember that #define is just REPLACING TEXT (always remember it)
exp:
#define something bySomethingElse...!##$%^&*
Where you use something, xcode will replace it by bySomethingElse...!##$%^&*
You should remove ";"
Good luck
No need of semicolon separator here.
#define MODE_DEV YES
#if (MODE_DEV)
#define WEBSERVICE_URL #"http://dev.testurl.com"
#else
#define WEBSERVICE_URL #"http://prod.testurl.com"
#endif
There is how it's done:
#define MODE_DEV YES
#if (MODE_DEV)
#define WEBSERVICE_URL #"http://dev.testurl.com"
#else
#define WEBSERVICE_URL #"http://prod.testurl.com"
#endif
NSURL *url = [NSURL URLWithString:WEBSERVICE_URL "/add_device_token"];

OBJ C Macro by Stringname

I try to get a macro by NSString value:
Example:
#define FOO1 NSLocalizedString (#"TEXT",#"COMMENT")
#define FOO2 NSLocalizedString (#"TEXT2",#"COMMENT2")
in .m File:
NSString *macroName = [NSString stringWithFormat:"FOO%d",1];
label.text = MACROBYNAME(macroName);
is there a way to do something like this?
Another approach to solution is a Switch-Case in the macro like this:
#define FOOSELECTOR(x) Switch x
case "FOO1"
NSLocalizedString (#"TEXT",#"COMMENT")
break;
case "FOO2"
NSLocalizedString (#"TEXT2",#"COMMENT2")
break;
or something like that... any Ideas?
Okay, I'll bite and make this an answer instead of a comment:
No, it's not possible. There's no way to do what you want to do.
Macros are evaluated during compile time, that's when you hit cmd-b in Xcode. Functions are called during runtime. That's when the program is run, possibly years after compilation.
Furhtermore, why do you want to do it? What's wrong with
NSString *localizedString = NSLocalizedString (#"TEXT",#"COMMENT");
label.text = [NSString stringWithFormat:#"%#%d", localizedString, 1];
?

objC Preprocessor NSString Macro

I have a problem to create a preprocessor macro function, that concatenates two Strings and "return" a NSString (#"...") value.
Here is what I tried:
#define ObjectKeyMake(NAME) #"com.test.##NAME"
if I print the result from a call I get:
NSLog(#"%#", ObjectKeyMake(foo)); // com.test.##NAME
so my question is: How can i concatenate 2 Strings in a preprocessor macro and "return" a NSString (#"..") ?
and no I can't use #define ObjectKeyMake(NAME) [#"com.test." stringByAppendingString: NAME] because i need a compile-time constant.
You can take advantage of the fact that the compiler combines string literals that are next to each other, like this:
NSString* greeting = #"Hello, " "world";
The macro implementation would look like this:
#define ObjectKeyMake(NAME) (#"com.test." #NAME)
#define ObjectKeyMake(NAME) #"com.test."#NAME

Objective-C macro to return a string with the function and the line number while accepting a string with a variable number of arguments?

I've found a bunch of macro variations on how to use NSLog as a basis and adding PRETTY_FUNC and LINE but all the variations of those macros simply output the result to the console.
I'd like to have a macro that can take a format with a variable number of arguments, add the name of the method and line number where it was called and then return an NSString but so far, the compiler always complains where I call it. My latest version is as follow:
#define FileLog(format, ...) {\
return [NSString stringWithFormat:#"\n %s [Line %d] \n %#",
__PRETTY_FUNCTION__,
__LINE__,
[NSString stringWithFormat:(format), ##__VA_ARGS__]];\
}
Each time I call it from my code, the compiler generates one of those errors:
error: expected expression before '{' token
I don't want to write a log class or use a framework for that. There must be a way to do that with a macro? Anyone?
Thanks in advance!
This is entirely possible with a macro, I think you just need a little more background on them.
First, macros are not functions, so the braces are unnecessary (and, in fact, are the cause of your error). A macro is really a fairly dumb "copy/paste" that is automated by the preprocessor, using syntax that it understands.
In order to define a macro that spans multiple lines and creates an NSString "in place", you have to escape the newlines with backslashes, like so:
#define FileLog(format, ...) \
[NSString stringWithFormat:#"\n %s [Line %d] \n %#", \
__PRETTY_FUNCTION__, \
__LINE__, \
[NSString stringWithFormat:format, ##__VA_ARGS__]]
Macros do not "return" like a function does, because, as I mentioned, they are merely a way to "copy/paste" text.
You can use it like so:
int num = 42;
NSLog(#"%#", FileLog(#"some number: %d", num));
If you were to look at the preprocessor output (the file that the preprocessor creates before compilation), the above example would expand to something like:
NSLog(#"%#", [NSString stringWithFormat:#"\n %s [Line %d] \n %#", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:#"some number: %d", num]]);
Try this....
Create an include file
#define LOG_NOLOG_LEVEL 0
#define LOG_ERROR_LEVEL 1
#define LOG_WARN_LEVEL 2
#define LOG_INFO_LEVEL 3
#define LOG_DEBUG_LEVEL 4
#if LOG_HELPER_LEVEL >= LOG_DEBUG_LEVEL
#define LOGDEBUG(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGDEBUG(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_INFO_LEVEL
#define LOGINFO(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGINFO(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_WARN_LEVEL
#define LOGWARN(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGWARN(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_ERROR_LEVEL
#define LOGERROR(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGERROR(...)
#endif
Then create a simple class LogHelper with a single class method as follows....
+ (void) log:(NSString *)message
{
fputs([message cStringUsingEncoding:NSUTF8StringEncoding], stderr);
}
Then in your code, you can put calls like...
LOGDEBUG(#"%s - %d Redirect response received\n%#",__FILE__,
__LINE__,[redirectRequest dumpInfo]);
You can set the LOG_HELPER_LEVEL to the level of logging you want to produce. If you set the level at say LOG_WARN_LEVEL, then no code will be included in your app for INFO or DEBUG levels, so it's easy to package your app up for release.
Hope this helps...
From Viraj Thenuwara, who was my iOS Senior developer who trained me :-)
This macro is much more simpler in its definition and also its usage, than the things mentioned above.
#define debug 1
#if debug
#define AppLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define AppLog(...)
#endif
And it's usage is as follows:
NSString *url = #"http://google.com";
AppLog(#"url %# and id %d", url, 5);
This AppLog line will print out it's given content only if the debug constant is equal to 1. At the Production time or in anytime you don't want to print the log lines you can disable it by turning that 1 into 0.
And it's console out put will be seen as follows:
Hope this will be helpful to someone else!
Cheers!

Are strings defined as constants not NSStrings?

I have a constant defined as:
#define BEGIN_IMPORT_STRING #"Importing Hands!";
But I get an error when I try to concat with:
NSString *updateStr = [NSString stringWithFormat:#"%#%#", BEGIN_IMPORT_STRING, #" - Reading "];
This doesn't happen if I replace it with a string literal
NSString *updateStr = [NSString stringWithFormat:#"%#%#", #"foo", #" - Reading "];
Or a local string
NSString *temp = #"foo";
NSString *updateStr = [NSString stringWithFormat:#"%#%#", temp, #" - Reading "];
You need to remove the semicolon from your #define:
#define BEGIN_IMPORT_STRING #"Importing Hands!"
To the compiler, the resulting line looks like this:
NSString *updateStr = [NSString stringWithFormat:#"Importing Hands!";, #" - Reading "];
Replace
#define BEGIN_IMPORT_STRING #"Importing Hands!";
with
#define BEGIN_IMPORT_STRING #"Importing Hands!"
This is because compiler in your case replaces all occurrences of BEGIN_IMPORT_STRING with #"Importing Hands!";
Aside from the accepted answer (remove semicolon), note that:
#"Foo" is an NSString. You can even send it a message.
#define FOO #"Foo" is a preprocessor macro, not a constant. It's a typing shortcut.
Though macros aren't an uncommon way to avoid retyping the same string, they're an unfortunate holdover. Essentially, they're playing games that aren't necessary anymore.
For repeated strings, I prefer:
static NSString *const Foo = #"Foo;
The const portion of this definition ensures that the pointer is locked down, so that Foo can't be made to point to a different object.
The static portion restricts the scope to the file. If you want to access it from other files, remove the static and add the following declaration to your header file:
extern NSString *const Foo;
Should you be using
NSLocalizedString(#"Importing Hands!", #"Message shown when importing of hands starts");
?
I put it as an answer because this looks like something you would not want to have to go and redo through all your code.