I am a mere beginner in iPhone Programming. I have seen this code in a tutorial which I didn't understand what does it means. I am confused about keywords such as titleForState and initWithFormat.
Can anyone help me to understand the meaning and importance of this syntax.
-(IBAction)buttonPressed: (id)sender {
NSString *title = [sender **titleForState**:UIControlStateNormal];
NSString *newText = [[NSString alloc] **initWithFormat**:
#"%# button pressed.", title];
statusText.text = newText;//statustext is a label
[newText release];
}
initwithFormat allows you to modify a string by adding a variable's value to it, you can add as many variables as you like but you have to add the correct symbol for the correct primitive type. Here are some examples
NSString *thisIsAString = #"String";
float thisIsAFloat = 13.9f;
NSString *strFormat = [[NSString alloc] initWithFormat:#"This is a %#, this is a %f float", thisIsAString, thisIsAFloat];
NSLog(#"%#", strFormat);
This will produce the output This is a String, this is a 13.9f float notice the float and the NSString value have replaced the symbols.
The titleForState is getting the title of an object that has that method. This will return the title for lets say a UIButton that has a title of "Press" for UIControlStateNormal so the value "Press" will be entered into the NSString title. Not though that not everything in sender has the method titleForState the reason this will show up is because sender is a primitive type of id this will cause and error if something is sent that hasn't got titleForState and your app will crash.
Related
I'm beginning to program iOS Apps and I want to know if its possible save the content of a label in a variable. I got this code:
if (event.subtype == UIEventSubtypeMotionShake) {
int randomNumber = arc4random() %2;
switch (randomNumber) {
case 0:
label.text = [NSString stringWithFormat:#"Out of luck"];
break;
case 1:
label.text = [NSString stringWithFormat:#"Yes, you can"];
break;
default:
break;
}
}
Then I want to use the label obtained in the shake event to tweet the result like this:
[twitter setInitialText:[NSString stringWithFormat:#"I asked the app and says:", label]];
But as I said before I'm a newby and I'm stuck here. ¿Any ideas?
Thank you in advance.
Have you tried this?
[twitter setInitialText:[NSString stringWithFormat:#"I asked the app and says: %#", label.text]];
Yes, it is possible to save the content of a label in a variable.
Actually, when you write
[NSString stringWithFormat:#"Out of luck"];
you are creating a NSString that can be used later in your application.
Just change it this way:
NSString *aString = [NSString stringWithFormat:#"Out of luck"];
Doing so you put "Out of luck" in aString.
Next step is getting back your string:
NSString *aString = [NSString stringWithFormat:#"Out of luck"];
label.text = aString;
Here you create your string aString and then you put its content "Out of luck" in your label.
You can obtain your goal in many different ways, for example you can write:
NSString *aString = #"Out of luck";
You have to practise variables and declarations... I suggest you to take a look at:
NSString Class Reference
The Objective-C Programming Language
You could also take a look at many posts that can be helpful like this:
Basic objective C variable declaration
EDIT: I just noticed that your question was more about labels than strings, so...
If you want to get your label content just write:
[NSString stringWithFormat:#"I asked the app and says: %#", label.text]
as Peter Zhou suggested.
label.text is writable, like in your code:
label.text = [NSString stringWithFormat:#"Out of luck"];
and readable:
NSString *theContentOfALabel = label.text;
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSString immutable allows to change its values?
I want to point to an object where in, if I make changes to one object. the same change has to reflect to other object. How to do that?
I have done a sample, but it is not working.
Please check the code once. What is the mistake in my code?
-(void)viewDidLoad{
str = [[NSString alloc] initWithString:#"Taruni"];
str2=str;
str2=#"Kalpana chawla";
[self changeStr:str];
NSLog(#"str = %#",str);
[str release];
[str release];
[super viewDidLoad];
}
-(void)changeStr:(NSString *)x
{
x=#"Chandra";
}
In .h file, I have declared in this way
#property(nonatomic,assign) NSString *str;
#property(nonatomic,assign) NSString *str2;
If I change the value of str2, str is not getting reflected.
How to do that?
Try below code,
-(void)viewDidLoad{
NSString *str = [[NSString alloc] initWithString:#"Taruni"];
NSString **str2 = &str;
*str2=#"Kalpana chawla";
[self changeStr:&str];
NSLog(#"str = %#",str);
[str release];
[str release];
[super viewDidLoad];
}
-(void)changeStr:(NSString **)x
{
*x=#"Chandra";
}
First of all, if you want to change the content of a string you need NSMutableString.
Second of all, in your changeStr: method you did nothing but assigned the "x" pointer to point to another string (and x is local).. In method your pointer "x" is local and assignment (x = something) will not reflect outside of that method. If you want to change something outside you will have to use x.propertyName or [x methodName]. If you want to change your input as to what string does it point to, you need input as :(NSString **)x, then *x = #"Chandra" and [self changeStr:&str].
Third of all, you can not change constant strings (defined like this: #"constant string"), you will have to use [NSString stringWithFormat:#"%#", str] (rather yet NSMutableString for your purpose)
//COPY THIS CODE IN A FRESH PROJECT!!!
//THIS 2 LINES ARE JUST EXAMPLES, OF VALUES PUSHES OUT A DATABASE
NSString *messagelevel1 = #"45";
NSString *currentlevel = #"1";
NSString *HuidigLevel = currentlevel;
NSDecimalNumber *huidigleveldec = [[NSDecimalNumber alloc] initWithString: HuidigLevel];
float HuidigLevelRek = [huidigleveldec floatValue];
//HERE IS THE PROBLEM
NSString* LevelTotaal=[[NSString alloc] initWithFormat:#"messagelevel%.f",HuidigLevelRek];
NSString*result = LevelTotaal;
NSLog(#"%#",result);
// THE ABOVE RESULT SHOULD RETURN THE SAME VALUE AS THE NEXT (messagelevel1) LINE BUT IT RETURNS ONLY "messagelevel1" AND NOT THE VALUE!
NSLog(#"%#",messagelevel1);
I want the *result string behaves like the *huidiglevel string and fetch some information, but because the LevelTotaal is a NSString, It doesn't fetch this information. I really got no idea where to google for this problem, searching the Developer docs didn't helped either . Maybe you guys can help me out?
Actually the second NSLog returns the value and to first NSLog just returns messagelevel1. To tell you in short ;)
I hope you guys get what I'm saying!
I think what you're trying to do is use variable variables, a system that does not exist in Objective-C. In PHP, you can use variable variables:
$hello = 'abcdef';
$varName = 'hello';
print $$varName; // prints the value of $hello, which is 'abcdef'
Like many things in PHP, this is not really a good way to design software. Instead, consider using something like a NSDictionary, this allows you to give specific data a key.
NSMutableDictionary *aDict = [NSMutableDictionary dictionary];
[aDict setObject:[NSNumber numberWithFloat:4.5] forKey:#"messageLevel1"];
NSString *result = [aDict objectForKey:#"messageLevel1"];
You can obtain the data dynamically, the key can be generated or obtained at runtime.
Edit:
Rather than having variables called messageLevel1, messageLevel2, messageLevel3 ... messageLeveln, just use an array.
NSMutableArray *messageLevels = [NSMutableArray array];
[messageLevels addObject:#"1"];
[messageLevels addObject:#"45"];
[messageLevels addObject:#"123"];
NSString *result = [messageLevels objectAtIndex:HuidigLevelRek];
NSDictionary *story = [stories objectAtIndex: indexPath.row];
cell.text=[NSString stringwithFormat:[story objectForKey#"message];
i dont knw what exaclty "message " contains (what is the meaning of objectForKey#"message")
EDIT CODE
NSString *key =[appDelegate.books objectAtIndex:indexPath.row];
//dict y=#"Name";
NSArray *nameSection = [dict objectForKey:key];
NSDictionary *story = [nameSection objectAtIndex: indexPath.row];
cell.text=[NSString stringwithFormat:[story objectForKey:key]];
NSLog(#"Value Of message: %#", [dict objectForKey:key]);
why my code crashes
If you are more familiar with Java or C# the code is equivalent to something like this:
// Assuming stories is declared as: List<Dictionary<string, string> stories;
Dictionary<string, string> story = stories[indexPath.row];
cell.Text = String.Format(story["message"]);
In Smalltalk-style (and therefore Objective-C too) Object Oriented programming, methods are more like messages to other objects. So a good Objective-C method name should read like an English sentence (Subject-Verb-Object). Because of this working with dictionaries (hash tables) looks like this:
[myDictionary setObject:#"Value" forKey:#"someKey"];
[myDictionary objectForKey:#"someKey"]; // == #"Value"
In Java it would be:
myDictionary.put("someKey", "Value");
myDictionary.get("someKey"); // == "Value"
Notice how the key ("someKey") was the first argument in the Java example. In Objective-C you name your arguments with the method name, hence setObject: forKey:. Also notice that in Objective-C strings start with an # symbol. That's because Objective-C strings are different from regular C strings. When using Objective-C you almost always use Objective-C's # strings.
In C# there is a special syntax for Dictionaries so it becomes:
myDictionary["someKey"] = "Value";
myDictionary["someKey"]; // == "Value"
One important problem that you might encounter if you're new is the problem of native types.
In Java to add an int to a Dictionary you used to have to do:
myDictionary.put("someKey", new Integer(10));
Because the primitive types (int, char/short, byte, boolean) aren't real Objects. Objective-C has this problem too. So if you want to put an int into a dictionary you must use NSNumber like so:
[myDictionary setObject:[NSNumber numberForInt:10]
forKey:#"someKey"];
And you pull out the integer like so:
NSNumber *number = [myDictionary objectForKey:#"someKey"];
[number intValue]; // == 10
EDIT:
Your code might be crashing if you have a '%' character in your string, since stringWithFormat is just like NSLog in that it takes many arguments. So if story["message"] is "Hello" then it'll work fine without extra arguments but if it's "Hello %#" you need to add one argument to stringWithFormat.
NSString *message = #"Hello %#";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:message forKey:#"message"];
NSString *output = [NSString stringWithFormat:[dict objectForKey:#"message"], #"World!"];
// output is now #"Hello World!".
#"message" is a key for a value stored in the NSDictionary object. The first line declares an NSDictionary named story that appears to come from an array.
If you want to find what value is stored for the key:#"message", consider using:
NSLog(#"Value Of message: %#", cell.text);
Run and check the console to see the output. (SHIFT + COMMAND + Y) in XCode will bring up the console, if that's what you are using. If you are unfamiliar with NSArrays/NSDictionaries, give Apple's Documentation a look.
I'm just guessing at all of this since that is a very limited sample of code. Try submit more code when you ask a question so that the viewers can get a better idea of your questions.
That is an example of key-value coding, and a lot of information is available on the Apple dev site if you're interested:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html
In the documentation for MKReverseGeocoder, the administrativeArea property gives you the current state the user is in, and it mentions in an example that it returns EITHER the state name OR its abbreviation. I am wondering if anyone knows how to get the abbreviation instead of the full state name...I have been able to find nothing that shows this is even a possibility besides that brief example that doesn't mention HOW.
Thanks!
I also needed to convert the State field from MKReverseGeocoder into a two letter abbreviation, so I created this plist:
https://github.com/djibouti33/US-State-Abbreviations
Here's how I use it:
// in my init
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"USStateAbbreviations" ofType:#"plist"];
self.usStateAbbreviations = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
// MKReverseGeocoder delegate method
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
...
NSString *state = [address objectForKey:#"State"];
NSString *stateAbbreviation = [self.usStateAbbreviations objectForKey:[state uppercaseString]];
NSString *stateTarget = state;
if (stateAbbreviation) {
stateTarget = stateAbbreviation;
}
...
}
There is no way to do this. Not sure why the Apple docs say "CA or California".
It's easy to convert state to 2 letter name. Just create a plist (table, or NSDictionary works too) of the following: http://www.usps.com/ncsc/lookups/usps_abbreviations.html and use that to look up the 2 letter abbreviations.