How concatenate a 2 constants - ios

I am having a few global variables declared in an NSObject class.
NSString *const SAT_NAME=#"http://you.com";
NSString *const DOMAIN= [NSString stringWithFormat:#"%#name/",SAT_NAME,nil];
I want to append the DOMAIN as shown (http://you.com/name/), but it does not work. How can i fix this ?

NSString *const SAT_NAME=#"http://you.com";
NSString *const DOMAIN= [NSString stringWithFormat:#"%#name/",SAT_NAME,nil];
Look at the format string. It starts with %#. The %# is replaced with "http://you.com". Now if you use copy and paste, you see that the result is
http://you.comname/
I don't quite see what you think the nil is good for. There is no formatting for it, so it is just ignored.

Related

How to append values in gloabal variables in iOS?

I am very much new to iOS so i don't have an idea.I am developing an application in which i am fetaching data from the server.So i have some of the url from which i will featch the data.I want to decalre all the url in a seperate file & use them in another file.I have created AppConst.h & AppConst.m.
AppConst.h
#import <Foundation/Foundation.h>
#interface AppConstant : NSObject
extern NSString const *BASE_URL;
extern NSString const *LOGIN;
extern NSString const *CREATE_ACCOUNT;
extern NSString const *UPDATE_PROFILE;
extern NSString const *ADD_BUSINESS_CARD;
extern NSString const *ADD_NONBUSINESS_CARD;
extern NSString const *ADD_EVENT_CARD;
#end
AppConst.m
#import "AppConstant.h"
#implementation AppConstant
NSString const *BASE_URL=#"http://localhost:8080/app/v1";
NSString const *LOGIN=#"/login";
NSString const *UPDATE_PROFILE=#"/create_account";
NSString const *ADD_BUSINESS_CARD=#"/addBusinessCard";
NSString const *ADD_NONBUSINESS_CARD=#"addNonBusinessCard";
NSString const *ADD_EVENT_CARD=#"addEventCard";
#end
But i am not able to append the string of BASE_URL with LOGIN url.
I get the error as below
sending 'const_NSString *__strong' to parameter of type "NSString discards qualifiers.
You should declare your constant string as follows:
NSString * const kSomeConstantString = #""; // constant pointer
The former is a constant pointer to an NSString object, while the later is a pointer to a constant NSString object.
Using a NSString * const prevents you from reassigning kSomeConstantString to point to a different NSString object.
The method isEqualToString: expects an argument of type NSString *. If you pass a pointer to a constant string (const NSString *), you are passing something different than it expects.
Besides, NSString objects are already immutable, so making them const NSString is meaningless.
Or else you can declare constant like this also
#define kSomeConstantString #""
better idea to make constants file is to create header file and add all the static constants like below:
// Host Url
#define BASE_URL #"http://localhost:8080/app/v1"
// login Url
#define LOGIN #"/login"
and than add the constants file.h in the parent view controller and than you can use everywhere in the app. and even if you want to append string than you can use the below code the create url from your code:
NSString *loginURL = [NSString stringWithFormat:#"%#%#", BASE_URL, LOGIN];
Thanks, May be help you to learn new things.

point a String to a list of constants and get the constant value

I'd like to know how is possible to point a String to a list of constants and get the constant value.
I have a list of hundreds constants declared in .m as follow:
NSString *const onenumber = #"2.58";
NSString *const twonumber = #"3.58";
NSString *const threenumber = #"2.72";
// and so on...
Below I have "myString" value that give me the same name of one of the constants:
NSString *myString= [[NSString alloc] initWithFormat:#"%#number", mynumber]; //mynumber isEqual to one,two,three etc...
How can I displayed the value of my number specified in the constant in a label without to use hundreds of if statements?
result.text= [[NSString alloc]initWithFormat:#"%#", ????? ];
Thanks for your answers in advance.

NSString concatenate on creation

I'm trying to concatenate 2 strings assigning the result to a new string.
Normally I would do this way:
NSString * s = [NSString stringWithFormat: #"%#%#", str1, str2];
Now I wish s to be static
static NSString * s = [NSString stringWithFormat: #"%#%#", str1, str2];
but compiler kick me with "Initializer element is not a compile-time..."
Is there any way to do this? I Googled a bit with no results and also I have not found answers on StackOverflow asking the question.
And what about using a short form like (in PHP)
$s = $str1.$str2;
Any help will be appreciated.
EDIT: What i want to achieve is to have a config file like this (in PHP code)
define ("BASE_URL", "mysite.com/");
define ("SERVICE_URL1", BASE_URL."myservice1.php?param1=value1");
define ("SERVICE_URL2", BASE_URL."myservice2.php?param2=value2");
I prefer to have all configurations strings in 1 file and i found usefull static strings in objective c. Just want to put 2 usefull thing together :)
EDIT2: There's no metter if i obtain this with defines, but the NSString way is preferred and i use static just beacause const make me some compilation problems i haven't solved yet
Use this code for creating static s:
static NSString * s = nil;
if (!s)
s = [NSString stringWithFormat: #"%#%#", str1, str2];
Also for concatenating two string you case use such code: NSString *s = [str1 stringByAppendingString: str2];
UPDATED:
You can concat static string by putting them one by one.
Example:
#define STR1 #"First part" #" Second part"
#define STR2 #"Third part " STR1
NSLog(#"%#", STR2);
This cole will print Third part First part Second part
I think below lines may help:
NSString *str1 = #"String1";
NSString *str2 = #"String2";
NSString *combinedStr = [str1 stringByAppendingString:str2];
If you can use a define, it is pretty simple:
#define A #"a"
#define B #"b"
…
static NSString *ab = A B; // or: #"A" #"B"
You can always concatenate string literals with a single space.
But something very important has to happen to use defines. What's wrong with computing it non-static or compute it once?
BTW: You should use dispatch_once() and not if. For the reasons you can search "dispatch_once" on SO.
If you don't mind compiling Objective-C++ code, you could simply change the extension from .m to .mm, by default XCode compiles according to file type, and this is valid in Objective-C++
Solved this way:
#define kBaseURL #"mysite.com/"
static NSString *kServiceUrl1 = kBaseURL #"myservice1.php?param1=value1";
static NSString *kServiceUrl2 = kBaseURL #"myservice2.php?param2=value2";
thanks all.
now the question is
wich one i have to accept as right answer? I mean, mine is the solution, but I would never have got there without your help guys

Objective-C: "format string is not a string literal (potentially insecure)" warning with macro

I'm using a macro to simplify returning localised strings, like so:
#define GetLocalStr(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:#"" table:nil], ##__VA_ARGS__]
Basically, if you have an entry in a localisation Strings file like "name" = "My name is %#";, calling
GetLocalStr( #"name", #"Foo" );
will return the NSString #"My name is Foo"
When I run it however, like:
NSString * str = GetLocalStr( #"name", #"Foo" );
I get the "format string is not a string literal" warning. Even following the advice of the other answers on SO about this warning and replacing it with:
NSString * str = [NSString stringWithFormat:#"%#", GetLocalStr( #"name", #"Foo" )];
I still get the warning, and besides, it kind of defeats the point of the macro making life easier.
How can I get rid of the warning short of wrapping all the GetLocalStr calls in #pragma suppressors?
Edit 27/08
After running through CRD's answer and doing some more tests, it seems like I made a bad assumption on the error. To clarify:
Localisation Strings file:
"TestNoArgs" = "Hello world";
"TestArgs" = "Hello world %#";
Code:
NSString * str1 = GetLocalStr( #"TestNoArgs" ); // gives warning
NSString * str2 = GetLocalStr( #"TestArgs", #"Foo" ); // doesn't give warning
The majority of my translations take no arguments, and those were the ones giving the warning, but I didn't make the connection until I read through CRD's answer.
I changed my single macro to two, like so:
#define GetLocalStrNoArgs(key) \
[[NSBundle mainBundle] localizedStringForKey:key value:#"" table:nil]
#define GetLocalStrArgs(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:#"" table:nil], ##__VA_ARGS__]
And if I call each one separately, there's no warnings.
I'd like GetLocalStr to expand to either GetLocalStrNoArgs or GetLocalStrArgs depending on if any arguments were passed or not, but so far I've been having no luck (macros are not my strong suit :D).
I'm using sizeof(#__VA_ARGS__) to determine if there's any arguments passed - it stringifys the arguments, and if the size is 1, it's empty (i.e. `\0'). Perhaps it's not the most ideal method, but it seems to work.
If I rewrite my GetLocalStr macro to:
#define GetLocalStr(key,...) (sizeof(#__VA_ARGS__) == 1) ? GetLocalStrNoArgs(key) : GetLocalStrArgs(key,##__VA_ARGS__)
I can use it, but I still get warnings everywhere it's used and there's no arguments passed, while something like
#define GetLocalStr( key,...) \
#if ( sizeof(#__VA_ARGS__) == 1 ) \
GetLocalStrNoArgs(key) \
#else \
GetLocalStrArgs(key,##__VA_ARGS__)
won't compile. How can I get my GetLocalStr macro to expand properly?
The Clang & GCC compilers check that format strings and the supplied arguments conform, they cannot do this if the format string is not a literal - hence the error message you see as you are obtaining the format string from the bundle.
To address this issue there is an attribute, format_arg(n) (docs), to mark functions which take a format string; alter it in some way without changing the actual format specifiers, e.g translate it; and then return it. Cocoa provides the convenient macro NS_FORMAT_ARG(n) for this attribute.
To fix your problem you need to do two things:
Wrap up the call to NSBundle in a function with this attribute specified; and
Change your "key" to include the format specifiers.
Second first, your strings file should contain:
"name %#" = "My name is %#"
so the key has the same format specifiers as the result (if you need to reorder the specifiers for a particular language you use positional format specifiers).
Now define a simple function to do the lookup, attributing it as a format translation function. Note we mark it as static inline, using the macro NS_INLINE as a hint to the compiler to both inline it into your macro expansion; the static allows you to include it in multiple files without symbol clashes:
NS_INLINE NSString *localize(NSString *string) NS_FORMAT_ARGUMENT(1);
NSString *localize(NSString *string)
{
return [[NSBundle mainBundle] localizedStringForKey:string value:#"" table:nil];
}
And your macro becomes:
#define GetLocalStr(key, ...) [NSString stringWithFormat:localize(key), ##__VA_ARGS__]
Now when you:
GetLocalStr(#"name %#", #"Foo")
You will get both the localised format string and format checking.
Update
After Greg's comment I went back and checked - I had reproduced your error and so assumed it was down to a missing attribute. However as Greg points out localizedStringForKey:value:table: already has the attribute, so why the error? What I had absentmindedly done in reproducing your error was:
NSLog( GetLocalStr( #"name %#", #"Foo" ) );
and the compiler pointed at the macro definition and not that line - I should have spotted the compiler was misleading me.
So where does that leave you? Maybe you've done something similar? The key is that a format string must either be a literal or the result of a function/method attributed as a format translating function. And don't forget, you must also had the format specifier to your key as above.
Update 2
After your additional comments what you need to use is function, rather than a macro, along with the format attribute, for which Cocoa provides the convenient NS_FORMAT_FUNCTION(f,a) macro. This attribute informs the compiler that the function is a formatting one, the value of f is the number of the format string and a is the number of the first argument to the format. This gives the function declaration:
NSString *GetLocalStr(NSString *key, ...) NS_FORMAT_FUNCTION(1,2);
and the definition (assuming ARC):
NSString *GetLocalStr(NSString *key, ...)
{
va_list args;
va_start(args, key);
NSString *format = [[NSBundle mainBundle] localizedStringForKey:key value:#"" table:nil];
NSString *result = [[NSString alloc] initWithFormat:format arguments:args];
va_end (args);
return result;
}
(which is essentially the same as #A-Live's).
Uses of this will be checked appropriately, for example:
int x;
...
NSString *s1 = GetLocalStr(#"name = %d", x); // OK
NSString *s2 = GetLocalStr(#"name = %d"); // compile warning - More '%" conversions than data arguments
NSString *s3 = GetLocalStr(#"name", x); // compile warning - Data argument not used by format string
NSString *s4 = GetLocalStr(#"name"); // OK
This variant produces no warnings (as there's always a va_list):
NSString* GetLocalStr1(NSString *formatKey, ...) {
va_list ap;
va_start(ap, formatKey);
NSString * format = [[NSBundle mainBundle] localizedStringForKey:formatKey value:#"" table:nil];
NSString *result = [[NSString alloc] initWithFormat:format arguments:ap];
va_end (ap);
return [result autorelease];
}
...
__unused NSString * str = GetLocalStr1( #"name", #"Foo" );
__unused NSString * str1 = GetLocalStr1( #"TestNoArgs" );
__unused NSString * str2 = GetLocalStr1( #"TestArgs", #"Foo" );
NSLog(#"%#", str);
NSLog(#"%#", str1);
NSLog(#"%#", str2);
Result:
my name is Foo
TestNoArgs
Hello world Foo
It doesn't answer the question exactly but might help you to avoid warnings until the solution is found.

#define value in stringFormat?

I have a define:
hashdefine kPingServerToSeeIfInternetIsOn "http://10.0.0.8"
then in code I with to use it:
NSString *theURL = [NSString stringWithFormat:#"%#", kPingServerToSeeIfInternetIsOn];
I get an exception.
What's the best way to define the const for the application and use it in a NSString init?
You've #defined it as a C string.
If you want it as an Objective-C String, you need
#define kPingServerToSeeIfInternetIsOn #"http://10.0.0.8"
Create a header file, e.g. MyAppConstants.h. Add the following:
extern NSString * const kPingServerToSeeIfInternetIsOn;
In the definition, e.g. MyAppConstants.m, add:
NSString * const kPingServerToSeeIfInternetIsOn = #"http://10.0.0.8";
In your class implementation, add:
#import "MyAppConstants.h"
You can use the constant as you have done already.

Resources