Returning Integer Value in Obj-C String - objective-c

I'm pretty new to Objective-C, switching over from C++, so excuse my stupid question.
I know with NSLogs and what not NSLog(#"%d is the index",i); is valid syntax. What is the reason that this: return [UIImage imageNamed:#"cover_%d.jpg", value]; isn't?
I get an error in my IDE telling me that I have too many arguments, i.e. the integer is never being used. How do I get the integer to reflect in a non-log situation?

[UIImage imageNamed:[NSString stringWithFormat:#"cover_%d.jpg", value]];
The string literal syntax doesn't support formats.

The %d (etc.) syntax is a specific convention used by particular functions like NSLog, it's not a general purpose Objective-C operation that you can expect to work with arbitrary method invocations.
Fortunately, another method that supports the %-substitutions is NSSTRing -stringWithFormat:. You use that method to create a string using the substitutions, then use that string as desired. For example:
NSString *imgName = [NSString stringWithFormat:#"cover_%d.jpg", value];
return [UIImage imageNamed:imgName];
(you could also combine these two lines into a single expression, eliminating the temporary imgName variable)

Related

Why are instances created using a 'literal syntax' known as 'literals'?

Something that is bothering me is why the term 'literal' is used to refer to instances of classes like NSString and NSArray. I had only seen the term used in reference to NSString and being naive I thought it had something to do with it 'literally' being a string, that is between quotation markers. Sorry if that sounds pathetic, but that was how I had been thinking about it.
Then today I learned that certain instances of NSArray can also be referred to as literal instances, i.e. an instance of the class created using a 'literal syntax'.
As #Linuxios notes, literal syntaxes are built into the language. They're broader than you think, though. A literal just means that an actual value is encoded in the source. So there are quite a few literal syntaxes in ObjC. For example:
1 - int
1.0 - double
1.0f - float
"a" - C-string
#"a" - NSString
#[] - NSArray
^{} - function
Yeah, blocks are just function literals. They are an anonymous value that is assignable to a symbol name (such as a variable or constant).
Generally speaking, literals can be stored in the text segment and be computed at compile time (rather than at run time). If I remember correctly, array literals are currently expanded into the equivalent code and evaluated at runtime, but #"..." string literals are encoded into the binary as static data (at least now they are; non-Apple versions of gcc used to encode an actual function call to construct static strings as I remember).
A literal syntax or a literal is just an object that was created using a dedicated syntax built into the language instead of using the normal syntax for object creation (whatever that is).
Here I create a literal array:
NSArray* a = #[#"Hello", #"World"];
Which is, for all intents and purposes equivalent to this:
NSArray* a = [NSArray arrayWithObjects:#"Hello", #"World", nil];
The first is called a literal because the #[] syntax is built into the language for creating arrays, in the same way that the #"..." syntax is built in for creating NSStrings.
the term 'literal' is used to refer to instances of classes
It's not referring to the instance really; after the object is created, the way it was created doesn't matter:
NSArray * thisWasCreatedWithALiteral = #[#1, #2];
NSArray * butWhoCares = thisWasCreatedWithALiteral;
The "literal" part is just the special syntax #[#1, #2], and
it ha[s] something to do with it 'literally' being a string, that is between quotation markers.
is exactly right: this is a written-out representation of the array, as opposed to one created with a constructor method like arrayWithObjects:

Pros and Cons of using [NSString stringWithString:#"some string"] versus #"some string"

I want to compare the following simple assignments:
...
#property(nonatomic,retain) UITextField *textField;
...
self.textField.text = #"some string";
self.textField.text = [NSString stringWithString:#"some string"];
self.textField.text = [NSString stringWithFormat:#"some string"];
Where textField is an UITextField and the text property a NSString. Of course all of them work. I know the difference of the last two when using parameters. But lets say we are only interested in this usage.
QUESTIONS:
For doing this kind of assignment, why shouldn't I always use the first one?
Comparing the last two, is there any difference for the compile- and/or runtime of these two? And why should I use stringWithString: at all if not?
Always try to do what feels natural. If you're assigning a constant string then do that, i.e. the first option. #"..." strings are very efficient constants that do not need to be memory managed, so use them if it makes sense.
NSLog(#"%p", #"XX");
NSLog(#"%p", #"XX");
NSLog(#"%p", #"XX");
Results in:
0xa2424
0xa2424
0xa2424
i.e. They are all the same object in memory.
NSLog(#"%p", [NSString stringWithString:#"XX"]);
NSLog(#"%p", #"XX");
NSLog(#"%p", [NSString stringWithString:#"XX"]);
Also results in:
0xa2424
0xa2424
0xa2424
As you can see from this there is no difference between the two objects, thus using -stringWithString: is just an extra message to send. Having said that, the overhead is usually not big enough to make a difference, so it shouldn't be a big deal either way. Personally I'd go with method one as there is no benefit of using method two, it's just extra code.
However,
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
Results in:
0x7f86730
0xf8479b0
0x8a4cdb0
As you can see, a new string is created each time as the sting you provide is just a format string that is used to process the following substitution variables, as you have none avoid stringWithFormat: unless you need it.
(Obviously all addresses are examples...)
For doing this kind of assignment, why shouldn't I always use the first one?
For that kind of assignment you would always use the first one, and never the last two.
why should I use stringWithString: at all if not?
Your intuition is correct. In most cases -stringWithString: is of dubious value. It's primarily meant for use with NSMutableString, which is a subclass of NSString.
For example:
NSMutableString* myString = [NSMutableString stringWithString:#"Foo"];
[myString appendString:#"Bar"];
You can also use it if you want to convert an NSMutableString to NSString, or otherwise ensure that you're dealing with an NSString instance. For example:
- (void):setMyString:(NSString*)newString
{
[_myString release];
_myString = [[NSString stringWithString:newString] retain];
}
That's one way to ensure that the _myString ivar is pointing to an NSString instance and not an NSMutableString instance. And the newString instance is only copied if necessary.
However, most developers would just use _myString = [newString copy]; in that case.
For doing this kind of assignment, why shouldn't I always use the first one?
You should always use the first one in the situation you describe. The second and third cases potentially copy the constant string, but the text property of UITextField is specified as copying the provided string anyway. There's no sense in making a copy of a constant string just so UITextField's -setText: can copy that copy.
Comparing the last two, is there any difference for the compile-
and/or runtime of these two? And why should I use stringWithString: at
all if not?
My understanding is that -stringWithFormat: will always create a new string, while -stringWithString: might not (probably doesn't) for a constant string. hypercrypt's results above are pretty telling in this respect; if you wanted to explore that more, you might try the same test with a mutable string.
I don't think it matters if you use the first or the second for strings.
I usually use the second one however.
In the case of the second and third, if you have another variable you would like to include in your string then you use the stringWithFormat one. Otherwise, use stringWithString.
int number = 5;
NSString *str = [NSString stringWithFormat:#"Number is: %i", number];
// Str is "Number is: 5"
Situation where you would use stringWithString:
NSString *myName = [NSString stringWithString:#"FN LN"];
// myName is "FN LN"
You would use the latter when you have no other variables to include in the string.
Also, this question has been answered countless times elsewhere.

Objective-C Calculating string value

This is my main:
int x=0;
NSString *new=[[NSString alloc]initWithString:#"9+4"];
x=[new intValue];
NSLog(#"hi %i",x);
This results in 9.. .since giving the intValue of a string will read only numbers and stops when the character is not a digit.
So how can i print the result of my string and get a 13 instead??
Actually, NSExpression was made just for this:
NSExpression *expression = [NSExpression expressionWithFormat:#"9+4"];
// result is a NSNumber
id result = [expression expressionValueWithObject:nil context:nil];
NSLog(#"%#", result);
NSExpression is very powerful, I suggest you read up on it. You can use variables by passing in objects through the format string.
Change this line
NSString *new=[[NSString alloc]initWithString:#"9+4"];
to
NSString *new=[NSString stringWithFormat:#"%f",9+4];
You will have to manually parse it. You could write a subclass of NSString that overrides the intValue method, and parses it to find arithmetic symbols and perform the math, but thats as close to automatic as you're gonna get I'm afraid
You will need to parse and evaluate it yourself, as seemingly simple calculations like this are beyond the scope of the basic string parsing Apple provides you. It might seem to be a no-brainer if you're used to interpreted languages like Ruby, Perl and the like. But for a compiled language support for runtime evaluation of expressions are uncommon (there are languages that do support them, but Objective-C is not one of them).
When attempting to parse an expression in a string you will want to use Reverse Polish Notation. Here is the first example I cam across in a google search for Objective-C.

Should I use an intermediate temp variable when appending to an NSString?

This works -- it does compile -- but I just wanted to check if it would be considered good practice or something to be avoided?
NSString *fileName = #"image";
fileName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
OUTPUT: TEST : image.png
Might be better written with a temporary variable:
NSString *fileName = #"image";
NSString *tempName;
tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
just curious.
Internally, compilers will normally break your code up into a representation called "Single Static Assignment" where a given variable is only ever assigned one value and all statements are as simple as possible (compound elements are separated out into different lines). Your second example follows this approach.
Programmers do sometimes write like this. It is considered the clearest way of writing code since you can write all statements as basic tuples: A = B operator C. But it is normally considered too verbose for code that is "obvious", so it is an uncommon style (outside of situations where you're trying to make very cryptic code comprehensible).
Generally speaking, programmers will not be confused by your first example and it is considered acceptable where you don't need the original fileName again. However, many Obj-C programmers, encourage the following style:
NSString *fileName = [#"image" stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
or even (depending on horizontal space on the line):
NSLog(#"TEST : %#", [#"image" stringByAppendingString:#".png"]);
i.e. if you only use a variable once, don't name it (just use it in place).
On a stylistic note though, if you were following the Single Static Assigment approach, you shouldn't use tempName as your variable name since it doesn't explain the role of the variable -- you'd instead use something like fileNameWithExtension. In a broader sense, I normally avoid using "temp" as a prefix since it is too easy to start naming everything "temp" (all local variables are temporary so it has little meaning).
The first line is declaring an NSString literal. It has storage that lasts the lifetime of the process, so doesn't need to be released.
The call to stringByAppendingString returns an autoreleased NSString. That should not be released either, but will last until it gets to the next autorelease pool drain.
So assigning the result of the the stringByAppendingString call back to the fileName pointer is perfectly fine in this case. In general, however, you should check what your object lifetimes are, and handle them accordingly (e.g. if fileName had been declared as a string that you own the memory to you would need to release it, so using a temp going to be necessary).
The other thing to check is if you're doing anything with fileName after this snippet - e.g. holding on to it in a instance variable - in which case your will need to retain it.
The difference is merely whether you still need the reference to the literal string or not. From the memory management POV and the object creational POV it really shouldn't matter. One thing to keep in mind though is that the second example makes it slightly easier when debugging. My preferred version would look like this:
NSString *fileName = #"image";
NSString *tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
But in the end this is just a matter of preference.
I think you're right this is really down to preferred style.
Personally I like your first example, the codes not complicated and the first version is concise and easier on the eyes. Theres too much of the 'language' hiding what it's doing in the second example.
As noted memory management doesn't seem to be an issue in the examples.

Advantage of data type id vs NSString in Objective C?

This code...
NSString * s = [[NSString alloc] initWithString:#"Hello, World"];
s = s.lowercaseString;
NSLog(#"%#", s);
...allows the use of dot notation but is strongly typed.
This code...
id s = [[NSString alloc] initWithString:#"Hello, World"];
s = [s lowercaseString];
NSLog(#"%#", s);
... is weakly typed and requires use of square brackets.
Other than that, is there any advantage of using one over the other?
If you're creating an NSString, then you might as well declare it as an NSString, and let the compiler help you.
The point of using id is to prevent strong coupling, and to use objects whose types are not known until a later time. e.g IBAction methods include the sender as a parameter as an id, because the exact type of the object isn't known.
Edited to add:
You may be new to the language, so I'll mention a couple of things
Firstly, where you have #"Hello, World", you already have an NSString, just one that is static. So you don't need to go through initWithString to create it. Just write:
NSString *s = #"Hello, World";
And, because you didn't alloc it, you don't have to worry about releasing it.
Secondly s.lowerCaseString. As Stephen has already answered, this is considered to be bad style. When you change a string to lower case, you aren't getting a property of the the string, you are causing an operation to be done on the string, in which case, you really should use bracket syntax.
Yes. The compiler warns you if you try to put a NSString into a method that expects a NSNumber.
It's more likely that the compiler finds your mistakes.
Arguably the former code is incorrect. You should only really use the dot notation to get/set properties, and lowercaseString is a method.
Otherwise, as you suggest, the only real difference is type safety. If you had a typo, say you put [a loercaseString], the compiler wouldn't shout at you.
There are certainly cases where you'd use id but your example is not one of them