NSLog only prints right value when I have a warning - objective-c

I'm getting garbage values when manipulating some of my NSString objects. I think the problem stems from my misunderstanding of how NSString works at a basic level. Below, I have a object which has a string pointer as a synthesized property. When I try to log it out directly, the compiler gives me a warning, but it does log out the value I expect. On the very next line, I try to log that string out the proper way but I end up getting garbage.
Code snippet
MyObject *object = [self.objects objectAtIndex:indexPath.row];
NSString *myString = object.myString;
NSLog(myString); // format not a string literal and no formal arguments
NSLog(#"formatted = %s", myString);
Output
2011-05-16 13:06:51.137 MyProgram[917:207] thisValueIsGood
2011-05-16 13:06:51.138 MyProgram[917:207] formatted = `å
This problem has snowballed onto other functions which use this final string. When I concatenate that string with other strings, I get even more garbage.

NSString is an object, instead of %s, use %#.

Related

stringByAppendingString on same object

i want to ask a question on NSString, the question is if
NSString str = #"Hello";
str = [str stringByAppendingString:#"World"];
if we NSLog the str we would get an output - HelloWorld!
So my question is if str is NSString class variable an its an static one (which can not be changed once it is defined) then how can we able to change it, (Note that I have used same NSString object str).
You haven't declared the string as static, but NSString is immutable. You are creating a new string and replacing str. Many Obj-C classes have a mutable type, so if you intended to modify your string as in this example, you might want something more like:
NSMutableString *str = [NSMutableString stringWithString:#"Hello"];
[str appendString:#" World"];
Note, #"Hello" is a NSString, so attempting to initialize a NSMutableString using that syntax would result in an error.
Actually, static variables can be changed once they are defined. Static variables are simply maintained throughout all function/instance calls. You can find a more detailed explanation here static variables in Objective-C - what do they do?. So the result would be the same. If the variable were defined as const (which cannot be changed) then you would get a compiler error. Generally speaking, the best way to figure these types of things out is to just try them on your own. If it's just a matter of writing a couple lines of code, or changing a keyword, what does it hurt?

what happens when stringWithFormat format has no type placeholders but has arguments

Suppose I have a method like this
+ (NSString *)stringWithObject:(id)object format:(NSString *)format
{
NSString *string = [NSString stringWithFormat:format, object];
NSLog(#"%#", string);
return string;
}
The object parameter is never nil but the format argument passed into the method might either be
NSString *formatWithPlaceholder = #"object: %#"
or
NSString *formatWithoutPlaceholder = #"No object";
so if formatWithoutPlaceholder is passed into the method as the format argument, the console output is correct and there are no warnings or errors, but will this cause other problems? I feel like there is something wrong about the usage of stringWithFormat: like this.
Nothing bad happens when the format string has fewer format specifiers than the number of parameters supplied: your code is valid for both format strings.
However, when the opposite situation happens (more format specifiers than the parameters) you get undefined behavior.

Warning - incompatible pointer types initializing 'NSString *__strong' with an expression of type 'UITextField'

I got this code and XCode warns me of "incompatible pointer types initializing NSString *__strong with an expression of type UITextField".
NSString *name = (UITextField *)searchText.text;
but this one is fine
NSString *name2 = [(UITextField *)searchText text];
and this one is fine too
NSString *name3 = [(UITextField *)searchText.text mutableCopy];
I have two questions:
I am confused with obj.* and [obj *]
Why is the "mutableCopy" correct is this case?
I don't know how to search in Apple developer documentation for these questions.
In the first version, due to operator precedence, you're casting searchText.text to a UITextField*, what you want to do is probably to cast searchText;
NSString *name = ((UITextField *)searchText).text;
In the second version you don't have the dot, so the compiler understands your cast to be casting searchText to UITextField and send the text message to it. In other words, exactly right.
The last case is a bit tricky since it involves both runtime and compile time. As I understand it;
You cast searchText.text to a UITextField*. The runtime still knows that the object is an NSString and the mutableCopy message that exists on both will go to the correct method [NSString mutableCopy] anyway and create/return a mutable copy of the NSString so runtime it works out ok.
Since mutableCopy returns id (referencing a NSMutableString), the assignment to an NSString is ok by the compiler (id can be assigned to anything), so compile time it's ok.
A question, what is searchText originally? That the last version compiled without warning indicates that it's already an UITextField*, or at least a type that can take the text message. If so, you should be able to just do;
NSString *name3 = [searchText.text mutableCopy];
In the second and third examples, the cast just operates on searchText. So with these you are sending a message to a UITextField object.
In the first one, the cast applies to the whole of searchText.text. Assigning a UITextField object to a NSString variables is not what you want. The code you're looking for is:
NSString *name = ((UITextField *)searchText).text;
The mutableCopy message returns a copy of your string as a NSMutableString object, which can be assigned to a NSString as NSMutableString derives from it. In this case using the 'copy' message is just as good.
Hope that helps.

NSArray and NSString

The book I'm currently reading has me write the following code :
-(IBAction)displaySomeText:(id)sender {
NSString *cow = #"Milk";
NSString *chicken = #"Egg";
NSString *goat = #"Butter";
NSArray *food = [NSArray arrayWithObjects:cow, chicken, goat, nil];
NSString *string = #"The shopping list is: ";
string = [string stringByAppendingString:[food componentsJoinedByString:#", "]];
[textView insertText:string];
}
I understand somewhat how arrays work but I need help understanding the following code
string = [string stringByAppendingString:[food componentsJoinedByString:#", "]];
I have never ever seen an instance where this is possible.
He has me create a 'string' object, from the NSString class, and then I'm doing this
string = [string stringByAppendingString:];
I'm confused. I have never seen an example where I create an object and then perform a method on the same object and store it in that exact same object.
For example, I know I can do this
NSSound *chirp;
chirp = [NSSound soundNamed:#"birdChirp.mp3"];
the above makes sense because I used the created object and performed a class method on it..
but I always assumed that the equivalent of the following code was NOT possible
chirp = [chirp methodNameEtc..];
I hope I explained my question well. If not I could always elaborate further.
I think this is the heart of your question "I'm confused. I have never seen an example where I create an object and then perform a method on the same object and store it in that exact same object."
To answer that question, your not actually 'storing it in the exact same object'. What you are doing is confusing pointers and objects.
Let's just look at this line:
string = [string stringByAppendingString:#"Hello"];
In this line 'string' is a pointer, not the object it points to. What this line of code is saying is:
"Object currently referenced by the pointer 'string', return to me a new NSString object whose text is your text with this text added. And when I get that new NSString object I ordered make the pointer 'string' point to that object instead."
string = [string stringByAppendingString:[food componentsJoinedByString:#", "]];
is the same as
NSString *tmpString = [food componentsJoinedByString:#", "];
string = [string stringByAppendingString:tmpString];
So in the example, the innermost square brackets are evaluated first, and then the outermost. Does that clarify it a bit? Thing of it like parentheses in math: (1*2*(1+2))... the innermost () get evaluated before you can determine that the real problem is 1*2*3. That is what is happening with [food componentsJoinedByString:#", "].
stringByAppendingString is not storing the string in the exact same object. It's one NSString object creating a new (autoreleased) NSString object.
There is no equivalent example for chirp (which is a NSSound object), unless you create your own category which extends NSSound with a method to return a brand new NSSound object.
Makes sense?
Oh, I also appreciate your Takizawa icon.

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) :)