Are strings defined as constants not NSStrings? - objective-c

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.

Related

Weird error with NSString: No known class method for selector 'stringWithBytes:length:encoding:'

I am attempting to use scanf to assign a value to an NSString, as per the answers to this question by Omar. This is the code, taken straight from progrmr's answer:
char word[40];
int nChars = scanf("%39s", word); // read up to 39 chars (leave room for NUL)
NSString* word2 = [NSString stringWithBytes:word
length:nChars
encoding:NSUTF8StringEncoding];
However, I'm getting an error on the last line that makes absolutely no sense to me:
No known class method for selector 'stringWithBytes:length:encoding:'
What in the world could be causing this error?
And yes, I do have #import <Foundation/Foundation.h> at the top of the file.
NSString does not have a stringWithBytes:length:encoding: class method, but you can use
NSString* word2 = [[NSString alloc] initWithBytes:word
length:nChars
encoding:NSUTF8StringEncoding];
Note however, that scanf() returns the number of scanned items and
not the number of scanned characters. So nChars will contain 1 and not the string length, so you should set nChars = strlen(word) instead.
A simpler alternative is (as also mentioned in one answer to the linked question)
NSString* word2 = [NSString stringWithUTF8String:word];
NSString does not respond to the selector stringWithBytes:length:encoding:. You probably wanted initWithBytes:length:encoding:.
Story in short: you might want to consider a const char C-string suitable initializer for your NSString object. Also, allocate memory before sending any initializer message to the NSString object. I would expect something like:
char word[40];
int nChars = scanf("%39s", word);
NSString *word2 = [[NSString alloc] initWithCString:word encoding:NSASCIIStringEncoding];
Note that initWithCString per design only supports properly null '\0' terminated 8-bit character arrays. For unterminated bytes arrays you have initWithBytes:length:encoding: instead.
For Unicode characters you could consider initWithCharactersNoCopy:length:freeWhenDone:.

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

Include a variable inside a NSString?

This works fine, we all know that:
NSString *textoutput = #"Hello";
outLabel.text = textoutput;
However, what if you want to include a variable inside that NSString statement like the following:
NSString *textoutput =#"Hello" Variable;
In C++ I know when I cout something and I wanted to include a variable all I did was soemthing like this:
cout << "Hello" << variableName << endl;
So I'm trying to accomplish that with Objective-C but I don't see how.
You can do some fancy formatting using the following function:
NSString *textoutput = [NSString stringWithFormat:#"Hello %#", variable];
Note that %# assumes that variable is an Objective-C object. If it's a C string, use %s, and if it's any other C type, check out the printf reference.
Alternatively, you can create a new string by appending a string to an existing string:
NSString *hello = #"Hello";
NSString *whatever = [hello stringByAppendingString:#", world!"];
Note that NSString is immutable -- once you assign a value, you can't change it, only derive new objects. If you are going to be appending a lot to a string, you should probably use NSMutableString instead.
I have The Cure you're looking for, Robert Smith:
if your variable is an object, use this:
NSString *textOutput = [NSString stringWithFormat:#"Hello %#", Variable];
The '%#' will only work for objects. For integers, it's '%i'.
For other types, or if you want more specificity over the string it produces, use this guide

\n does not skip to next line in NSString

NSMutableString *a = #"Hi";
NSMutableString *b =[a stringByAppendingString:#"\n\n Hi Again"];
The above doesn't give an error but does not put "Hi Again" on the next line. Why?
EDIT2
I realised after posting, that the OP had NSString in the title but put NSMutableString in the code. I have submitted an edit to change the NSMutableString to NSString.
I will leave this as it still maybe helpful.
Well I am surprised that does not give an error, because you are giving a NSMutableString a NSString.
You need to read the Documentation on NSMutableStrings.
to give you an idea
//non mutable strings
NSString *shortGreetingString = #"Hi";
NSString *longGreetingString = #"Hi Again";
/*mutable string - is created and given a character capacity The number of characters indicated by capacity is simply a hint to increase the efficiency of data storage. The value does not limit the length of the string
*/
NSMutableString *mutableString= [NSMutableString stringWithCapacity:15];
/*The mutableString, now uses an appendFormat to construct the string
each %# in the Parameters for the appendFormat is a place holder for values of NSStrings
listed in the order you want after the comma.
Any other charactars will be included in the construction, in this case the new lines.
*/
[mutableString appendFormat:#"%#\n\n%#",shortGreetingString,longGreetingString];
NSLog (#"mutableString = %#" ,mutableString);
[pool drain];
I think this might help you. You'd rather to use '\r' instead of '\n'
I also had a similar problem and found \n works in LLDB but not in GDB
Try using NSString. You could use:
NSString *a = [NSString stringWithFormat:#"%#\n\n%#", #"Hi", #"Hello again"]
If your string is going in a UIView (e.g a UILabel), you also need to set the number of lines to 0
myView.numberOfLines=0;

stringByAppendingFormat not working

I have an NSString and fail to apply the following statement:
NSString *myString = #"some text";
[myString stringByAppendingFormat:#"some text = %d", 3];
no log or error, the string just doesn't get changed. I already tried with NSString (as documented) and NSMutableString.
any clues most welcome.
I would suggest correcting to (documentation):
NSString *myString = #"some text";
myString = [myString stringByAppendingFormat:#" = %d", 3];
From the docs:
Returns a string made by appending to the receiver a string constructed from a given format string and the following arguments.
It's working, you're just ignoring the return value, which is the string with the appended format. (See the docs.) You can't modify an NSString — to modify an NSMutableString, use -appendFormat: instead.
Of course, in your toy example, you could shorten it to this:
NSString *myString = [NSString stringWithFormat:#"some text = %d", 3];
However, it's likely that you need to append a format string to an existing string created elsewhere. In that case, and particularly if you're appending multiple parts, it's good to think about and balance the pros and cons of using a mutable string or several immutable, autoreleased strings.
Creating strings with #"" always results in immutable strings. If you want to create a new NSMutableString do it as following.
NSMutableString *myString = [NSMutableString stringWithString:#"some text"];
[myString appendFormat:#"some text = %d", 3];
I had a similar warning message while appending a localized string. This is how I resolved it
NSString *msgBody = [msgBody stringByAppendingFormat:#"%#",NSLocalizedString(#"LOCALSTRINGMSG",#"Message Body")];