Error with a NSLocalizedString with parameter - objective-c

I have to print a localized string passing it a parameter.
I use:
NSString *myMsg = [[NSString alloc]
stringByAppendingFormat:NSLocalizedString(#"MyKey", #""), aString];
[MyViewController updateMyMessage:myMsg];
[myMsg release];
In the Localizable.strings, I use:
"MyKey" = "My message says: %#";
EDIT:
It works, using this code:
NSString *myMsg = [NSString stringWithFormat:NSLocalizedString(#"MyKey", #""), aString];
[MyViewController updateMyMessage:myMsg];
However, I would to know what's the problem in the the former code.

Fran,
stringByAppendingFormat appends to an existing string. Since myMsg has not been initialized the first example doesn't work.
You can reference: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html and make sure you are using a method for creating or initializing strings.
Hope that helps,
Ryan

Related

Repointing a pointer inside an Objective-C method

Firs of all, sorry if my english is not absolutely correct. It's not my native language but I'll try to explain myself the best I can.
I'm having a hard time trying to understand the following issue. Take in account the following code:
// On a class named SPOTest
- (void)referenceTest:(NSMutableString *)originalText
{
[originalText appendString:#" world!!!"]
}
// From another place
NSMutableString *myText = [NSMutableString stringWithString:#"Hello"];
NSLog(#"Contents of myText BEFORE: %#", myText);
SPOTest *myTest = [[SPOTest alloc] init];
[myTest referenceTest:myText];
NSLog(#"Contents of myText AFTER: %#", myText);
The output:
Contents of myText BEFORE: Hello
Contents of myText AFTER: Hello world!!!
I find it understandable. I'm working with pointers so if I change the thing and the end of a pointer, I'm changing that thing for all the pointers pointing to it. On the other hand, if I change the code and do this:
// On a class named SPOTest
- (void)referenceTest:(NSMutableString *)originalText
{
NSMutableString *newText = [NSMutableString stringWithString:#"Hello world!!!"];
originalText = newText;
}
// From another place
NSMutableString *myText = [NSMutableString stringWithString:#"Hello"];
NSLog(#"Contents of myText BEFORE: %#", myText);
SPOTest *myTest = [[SPOTest alloc] init];
[myTest referenceTest:myText];
NSLog(#"Contents of myText AFTER: %#", myText);
Then I get this:
Contents of myText BEFORE: Hello
Contents of myText AFTER: Hello
Why is that? I suppose the correct way to do this is to use a double indirection and an implementation similar to the one used with NSError mechanism but I want to understand why I'm obtaining this behavior. If I can change the contents and the end of myText pointer from the referenceTest: method in the first example, why can't I change the address of myText from the same method in the second example?
I know I'm missing something trivial but I can't find it and I'd like to understand this to better understand the reasoning behind NSError mechanism.
Thank you!
In the second case you're changing the local copy of that pointer. If you want to repoint it in the calling scope, you'd need to use a pointer to a pointer, i.e.:
- (void)referenceTest:(NSMutableString **)originalText
{
NSMutableString *newText = [NSMutableString stringWithString:#"Hello world!!!"];
*originalText = newText;
}
And call it thusly:
[myTest referenceTest:&myText];
And it is worth noting that stringWithString returns an autoreleased string, which means your function is too.
There's a difference between objects and pointers to objects.
Someone has created an NSMutableString object, which exists somewhere in memory. We don't really care where it is. That someone received an NSMutableString* which points to the NSMutableString object. A copy of that NSMutableString* was given to your method referenceTest. There can be any number of pointers to that NSMutableString object, but there is only one object.
The appendString method changes the NSMutableString object itself.
The stringWithString method creates a new NSMutableString object and returns a pointer to it. So now we have two objects, and newText is a pointer to the second one. When you assign newText to originalText, originalText becomes a pointer to the second NSMutableString object. However, originalText is just the parameter in your method. The pointer that the calling method holds isn't changed by this.

Understanding Instantiation in Objective-C

I’m currently trying to learn Objective-C by reading books and online tutorials, also referring to the Apple documentation but some things just don’t click. I have a question about classes, I have been using the NSString for a while now without putting too much attention on how it is used.
I was under the impression that in order for someone to be able to use a method from a certain class in Objective-C you first needed to instantiate it, something like…
ClasssName *varName = [[ClassName alloc]init];
Then you would call methods like...
[varName someMethod];
But looking at how the NSString is used I’m now I little confused, for instance here is how we would normally use it...
NSString *someString = #"some text here";
[someString stringByAppendingFormat: #"some text = %d", 3];
Following what I have read about classes we would need to do something like the following instead.
NSString *someString = [[NSString alloc]initWithString: #"some text here"];
[someString stringByAppendingFormat: #"some text = %d", 3];
Can someone explain why some classes do not require instantiation before using its methods?
Objective-C knows some abbreviations that are called literals. The compiler is aware of the special notation. A string literal is compiled into the binary and exits throughout the lifetime of an app.
For most cases it will behave like an object created on runtime.
if two literals are identical, only one object will be created and live forever
if you create NSString *string = [[NSString alloc] initWithString:#"My String"]; with #"My String" being used as a literal before, also string can point to it.
Since Apple LLVM Compiler 4.0 Objective-C knows some more literals. But in contrast to string literals these literals are created during runtime through convenient initializers.
Note that
[someString stringByAppendingFormat: #"some text = %d", 3];
does not change someString. It returns a new string object.
NSString *newString = [someString stringByAppendingFormat: #"some text = %d", 3];
The #"Text" syntax gives you an autoreleased string back, it can be thought of as a shorthand.
when you write
[[NSString alloc]initWithString: #”some text here”];
you conceptually create an autoreleased string with #”some text here” and then you create a retained new string with initWithString.

Too many arguments to method call

I am trying to set the initial text for what the twitter message should say in my app using a NSString from my appDelegate. Check out the code here:
NSString *tweet;
tweet=[MyWebFunction tweet:appDelegate.stadium_id];
if([deviceType hasPrefix:#"5."]){
// Create the view controller
TWTweetComposeViewController *twitter = [[TWTweetComposeViewController alloc] init];
[twitter setInitialText:#"#%",tweet];
The problem is, is there is an error at the twitter setInitialText that there are Too many arguments to method call, expected 1, have 2. ?!?!?
Any help is greatly appreciated. :)
The TWTweetComposeViewController method setInitialText only takes one argument, being of type NSString*. You cannot simply format any and all NSString variables passed to a method as you can with the NSString method stringWithFormat (which is, I imagine, where you've seen the syntax [NSString stringWithFormat:#"%#", myString]).
In your case, you either need to simply call:
[twitter setInitialText:tweet];
or call:
[twitter setInitialText:[NSString stringWithFormat:#"%#", tweet]]
EDIT
I feel it necessary to add, to further your understanding, that a method only takes a variable number of arguments (such as stringWithFormat) when its declaration ends with ...
For example, looking in the docs for NSString reveals that stringWithFormat is declared as such:
+(id) stringWithFormat:(NSString *)format, ...;
Similarly, arrayWithObjects in NSArray is declared as such:
+(id) arrayWithObjects:(id)firstObj, ...;
which one would use like:
NSString* myString1 = #"foo";
NSString* myString2 = #"bar";
NSNumber* myNumber = [NSNumber numberWithInt:42];
NSArray* myArray = [NSArray arrayWithObjects:myString1, myString2, myNumber, nil];
Try [twitter setInitialText:tweet];
If you really need formatted text for a more complex case, try
[twitter setInitialText:[NSString stringWithFormat:#"%#", tweet]];
"[twitter setInitialText:#"#%",tweet];"
you just got your "#" and your "%" the wrong way round it should be
[twitter setInitialText:#"**%#**",tweet];

Assign to NSString after alloc/init

This doesn't seem to work:
NSString *string = [[NSString alloc] init];
string = #"%#M", anotherstring;
I expect this to make "string" equal to "5M" if "anotherstring" is "5".
Is this not the right syntax? Now, I could use initWithFormat and it would work, but how can you separate it into two different lines and also work?
There are two mistakes in your code. Firstly, NSStrings are immutable, and once you allocate and initialize them, they're set, and there's no way to change them. For that, you'd have to look into NSMutableString.
Secondly, the syntax of your code makes no sense. #"%#M", anotherString is not a valid Objective-C method call. You are indeed looking for -initWithFormat: to perform the operation you want. The code should look like this:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Read more about NSString and how to use it in the NSString Programming Reference document, and the String Programming Guide to get a sense of how to work with strings in Cocoa and Objective-C.
This line:
string = #"%#M", anotherstring;
is syntactically correct, but it doesn't do what you want it to do. This is how you format a string:
NSString *string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
There's no point in separating it into two lines. This:
NSString *string = [[NSString alloc] init];
string = [[NSString alloc] initWithFormat:#"%#M", anotherstring];
will create an extra NSString object, and also cause a memory leak.
How about
NSString* string;
string = [[NSString alloc] initWithFormat:#"%#M", anotherString];
Keep in mind that the = operator is assignment. Any time you use it, any value was stored in your variable is overwritten with the new one. So even if your original code was syntactically correct it still has faulty semantics that would, in this case, cause a memory leak.
just make it into a property and you dont need to worry about releasing and retaining the "string" (that is if you autocreate it by using synthesize). and dont forget to autorelease the object ur assigning to the property:
self.string = [[[NSString alloc] init] autorelease]

Objective-C: How do you append a string to an NSMutableString?

URL Download
http://code.google.com/p/mwiphonesdk/source/browse/#svn/trunk/iMADE/PrepTasks/08
I have code at the location at the link above and I am using NSMutableString to append strings as data is downloaded. But I am finding that using appendString does not increase the length of the mutable string. I must be doing something wrong.
And when I am done I need to convert NSMutableString to NSString to return it. I have looked for examples to do this but I do not see any yet.
I am most familiar with Java and C# where there is a StringBuffer/StringBuilder which allows you to append pieces and them simply call toString at the end to get a String. It does not appear to be this easy in Objective-C.
NSString* str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
#pragma mark TODO Confirm this is appending a value to the mutable string
[self.mutableString appendString:str];
NSLog(#"str length: %d, %d", [str length], [self.mutableString length]);
Above is the section of code that calls appendString.
I see that str has a length > 0 but calling appendString does not increase the length of self.mutableString.
What am I doing wrong here?
As for having an NSMutableString* and needing to return an NSString*, the former is a subclass of the latter so anywhere you see an NSString* an NSMutableString* will suffice as-is.
Your code looks OK from what you've posted. The only thing I can think of is that perhaps there isn't any data to speak of when initializing the str variable. In such a case appending an empty string will do nothing to mutableString.
You'll also want to make sure self.mutableString has been properly allocated and initialized. You can send messages to NSObject*s that are nil which may be misleading when [self.mutableString length] returns 0.
I have fixed the problem. I simply was not initializing the NSMutableString value and it was transparently not doing anything.
Before appending the string I put the following code.
if (_mutableString == nil){
_mutableString = [[NSMutableString alloc] init];
}
Thanks everyone for answering. And it is good to know that I can use NSMutableString in place of NSString. (that is too easy) :)