Label text not updating (cocos2d) - objective-c

I have a class which I intend to reuse for a game with multiple levels and I'm having a problem with updating the label text. Basically, I'm trying to reuse this class for 15 levels of a game. So initially the value of the label is 1 then it should increase by one after the level has been cleared then the class is reloaded with the updated text. This is how I'm trying to update my label:
GameScene *stage= [stage node];
[[CCDirector sharedDirector]replaceScene:stage];
//stageNo is an integer that I pass to the label as it's text value. As long as its less that 15, it should go inside that code block.
if(stageNo < 15)
{
stageNo = stageNo + 1;
[stage.layer.stageLabel setString:[NSString stringWithFormat:#"%i", StageNo]];
}
This only works only once so if the default value of the label is 1, after the class is reloaded it becomes 2. After that, it's just stuck to 2. So my question is, how can I update the label text whenever the class is reloaded to increment by 1?

Seems like this is most definitely a scope problem. According to your comments you've done the right thing and created a property called stageLabel. The only problem is when you set it up initially you are not retaining it.
Instead of using
stageLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"%#", stageNo] fontName:#"Arial" fontSize:18];
you should use
self.stageLabel = [[CCLabelTTF alloc] initWithString:[NSString stringWithFormat:#"%#", stageNo] fontName:#"Arial" fontSize:18];

Separate the UILabel declaration from stringWithFormat in the init(). it then should work

Related

How to choose a method based on an element of an NSArray (Objective-C)

I'm writing a sort of calculator app. I have a UIPickerView (1 column) loading data from an NSArray of strings. The user will select one of these (it's selecting which type of calculator to use -- each uses a different method to calculate). The user inputs some things into some UITextFields and then presses a UIButton to do the calculations.
My NSArray is this:
calcNames = [NSArray alloc] initWithObjects:#"first", #"second", #"third", nil];
And my methods are called firstCalc(input1, input2, input3), secondCalc(input1, input2, input3), and so on. (The inputs are coming from the UITextFields.)
When I press the button, I would like to tell it to look at what the selection in the UIPickerView is and run the corresponding method without just typing an if-then statement for each one (it's very inconvenient to do this for reasons specific to my app, which are beyond the scope of this discussion).
So I have already defined a way to determine what the selected calc is:
selectedCalc = [[NSString alloc] initWithString:[calcNames objectAtIndex:row]]
where 'row' is the current selection in the UIPickerView.
Now I have a doCalculations method for when someone presses the UIButton:
-(IBAction)doCalculations:(id)sender {
// save the data input
double input1 = [input1Field.text doubleValue];
double input2 = [input2Field.text doubleValue];
double input3 = [input3Field.text doubleValue];
// do the calculations
int i;
for (i = 0; i < [calcNames count]; i++) {
if (selectedCalc == [calcNames objectAtIndex:i]) {
// do calculations here
double numResult = ??????
// if selectedCalc is "first", I want it to do firstCalc(input 1, input 2, input 3)
// if selectedCalc is "second", I want it to do secondCalc(input 1, input 2, input 3), and so on
// the rest is just for displaying the result
NSString* result = [NSString stringWithFormat:#"The answer is %f", numResult];
[resultLabel setText:result];
}
}
}
So basically, it runs a for loop until it finds which calculator is selected from the UIPickerView and when it finds it, runs the calculations and displays them.
I've been trying to understand if maybe function pointers or selectors (NSSelectorFromString?) are the right things to use here and how to use them, but I'm really struggling to understand where to go after a couple days of reading Apple's documentation, Stack Overflow questions, playing with sample code, and tinkering with my own code.
Sorry if the question is too lengthy, I thought it may be more helpful to others looking for assistance in the future to see the full idea. (At least I know sometimes I'm lost with these question pages.)
I would be very grateful for any assistance,
Ryan
You can dynamically invoke a method using a selector. You could for example have a secondary array to calcNames with selector called calcSelectors:
SEL calcSelectors[] = (SEL[3]){
#selector(first:arg:),
#selector(second:arg:),
#selector(third:arg:)};
Calling the right method would then be as simple as:
[self performSelector:calcSelectors[calcIndex] withObject:arg1 withObject:arg2];
If you need more then 2 arguments, then you also need to mess a bit with a NSInvocation instance to setup the call.
Example 1:
NSString *method=[calcNames objectAtIndex:0];//here play with objectatindex
SEL s=NSSelectorFromString(method);
[self performSelector:s];
which will call this method
-(void)first{
NSLog(#"first");
}
-----------------------------------------
Example 2:
NSString *totalMethodName;
totalMethodName=#"vijay";
totalMethodName=[totalMethodName stringByAppendingString:#"With"];
totalMethodName=[totalMethodName stringByAppendingString:#"Apple"];
SEL s=NSSelectorFromString(totalMethodName);
[self performSelector:s];
will call
-(void)vijayWithApple{
NSLog(#"vijayWithApple called");
}
You can make use of NSInvocation to dynamically bind multiple arguments to a selector. Follow this post to learn it.
If you are going to use NSInvocation you have to define your methods in the objective-C way something like the following.
- (double)firstCalcWithInput1:(double)input1 input2:(double)input2 andInput3:(double)input3;
- (double)secondCalcWithInput1:(double)input1 input2:(double)input2 andInput3:(double)input3;

Subtract one from integer displayed in UILabel

I have a UILabel that adds one to its value -- basically it counts up -- when a button is pressed. Could someone please help me with a minus button? That way if the user accidentally presses the add button more than they needed, they can subtract their mistake. I've tried this, but the label's text is set to -1 now. and I want it to just subtract one each time its pressed:
- (IBAction)subtractButton:(id)sender {
static int integerSaved;
integerSaved = integer;
integerSaved -= 1;
[label2 setText:[NSString stringWithFormat:#"%i", integerSaved]];
}
Try this:
- (IBAction)subtractButton:(id)sender {
[label2 setText:[NSString stringWithFormat:#"%d",[label2.text intValue] - 1]];
}
-(void)subtract
{
label2.text = [NSString stringWithFormat:#"%d", [label2.text intValue]-1];
}
This code assumes that you are not using Interface Builder, and that you are manually linking "subtract" to the UIButton. If you are using Interface Builder, try this code.
-(IBAction)subtract:(id)sender
{
label2.text = [NSString stringWithFormat:#"%d", [label2.text intValue]-1];
}
I have not tested this but I think it should work. Good luck!
Using the value of the UIView instance to do arithmetic is not the MVC-way. You should really be separating your data model from your view.
Expose an int, NSInteger or NSNumber property in a class somewhere, where that class is dedicated to holding data values for your app.
When a touch event comes in for a given button, increment the data property and fire a notification that updates the view based on what's in the property. Or add an observer to the property. The observer then updates the view when the property value changes.
Following the MVC pattern would be a more "Apple"-ish or "iOS"-ish way of doing things, than getting the UIView's value, converting it to an integer, and then converting it back to a string.

Create multiple UITextFields programmatically using a for loop

Brand new to coding; been utilizing stackoverflow religiously for months; first time asking a question; please be gentle.
I'm trying to create a series of UITextFields programmatically using a for loop. The fields should have names like "pax1name", "pax2name", "pax3name", etc.
The piece I'm missing is how to take a string and make it the name of a textField, changing the name of the textField each time the for-loop executes.
Here's my code, but maybe I'm going about this the wrong way? Thank you in advance!
// set up the names textfields
for (int i = 0; i < 7; i++) {
NSString *fieldName = [[NSString alloc] initWithFormat:#"pax%iname", (i + 1)];
// I can't figure out what goes here to create a UITextField with the name of fieldName
textField = [[UITextField alloc] initWithFrame:CGRectMake(15, (15 + (i * 40)), 400, 40)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15.0];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[namesViewController addSubview: textField];
[fieldName release];
[textField release];
}
Normally you use the UIView property tag for that. Use [textField setTag:<youCustomTag>] in your loop to set the value, e.g. your variable i. Please note that tag expect an NSUInteger and not an NSString.
To access the correct text field afterwards you'd call [[namesViewController view] viewWithTag:<yourCustomTag>].
BUT, is it really necessary to create multiple text fields for your view controller? There might be a more elegant solution by creating just one single text field and setting the tag-property on demand when the user taps a row. I don't know if that would work for you.
I think you've been going the wrong way about this. UITextField has no property called "name". To identify a control, you can use its tag property. See this code:
for (int i = 0; i < 7; i++) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(...)];
textField.tag = i + 1;
...
}
When you say the name of the textfield I'm presuming you mean the variable name rather than setting the text that is displayed. I.e. you want to create the variables in a loop, but later be able to reference them individually by name.
In that case, you can't do what you want to do. What you can do is stick them in an array for handy access later on.
NSMutableArray *paxNameFields = [[NSMutableArray alloc] init]; // before your loop
[paxNameFields addObject: textField]; // inside the loop
[paxNameFields objectAtIndex: 5]; //sometime later use the 6th field
Or if you just want to be able to identify which UITextField you're passed into a delegate callback later on, you can set/check the tag property.
UITextFields don't HAVE names. You're probably coming from HTML-world, where these things are basically a big hash of name-value pairs. Not like that in Cocoa Touch. As #Florian Mielke says, they each have an int .tag property, which is probably what you want to set.

How do I receive the current value of a slider in code?

I am (attempting) developing my first application in Xcode using cocoa framework.
I have a slider which min value is 10 and max is 50. This is to select max search results.
I have linked a label on my user interface to display the value of the slider and when it is moved, it updates the label on the user interface.
However, I am trying to join around 4 strings to create my final URL one of them is the value of said label.
I am trying to read the value of the label on the interface for use in creating the finished URL
NSString *startofURL = #"http://starturl.com/?q=";
NSString *searchTerm = whatToSearch;
NSString *middleofURL = "&max-results=";
NSString *resultsStr = labelMaxResults.stringValue; //Problem here ??
I have 2 questions; firstly, How do I go about retrieving the value of my slider via code instead of trying to get it from the linked label, as I think this is my problem.
secondly, I have read up on joining and appending strings, however I am a little confused on which is the best method to use in order to join up the 4 strings into one long URL.
NSSlider * slider = [[NSSlider alloc] init];
[slider setMinValue:50];
[slider setMaxValue:150];
int sliderValue = [slider intValue];
this doesn't put your slider on screen, but assume you made it in IB, ignore the first line, you can set your min max and get the value.
you can make an action like
-(IBAction)sliderMoved:(id)sender
then bind that to the slider, if you set the slider to continuous you will get updates every time that it moves other wise just when you let go of the slider
-(IBAction)sliderMoved:(id)sender
{
sliderValue = [slider intValue];
[self doSomethingElseNow];
}
For the first part of your question, it depends which OS you are using as to which process to use.
If you are using OS X, the best way to get a value for your slider is to create a binding in IB for your slider. To do this, click on the slider in IB and go to the bindings section. In the Value section, click on Value and select the class you wish to use the value in as your Bind To class (I'm going to use MyClass for this example). Then for the model key path, assign it to some value of your choice. For the purpose of this, I'll just call it sliderValue.
Then in MyClass.h, you must set up the following:
#interface MyClass : <your class type> {
int sliderValue;
}
#property (readwrite, assign) int sliderValue;
In MyClass.m, you'll need to synthesize the value.
#synthesize sliderValue;
At this point, you should be able to get the value of your slider at any point in your code by calling [self sliderValue].
If you are, however, using iOS, then all you have to do is call the value property from your slider. So if you have the a UISlider *mySlider, all you have to do is call mySlider.value to get the current value of your slider.
For your second question, you can go about this two ways. If you want to append the strings, simply follow the format:
NSString *appendedString = #"";
appendedString = [appendedString stringByAppendingString:string1];
and so on until you have all your strings into your URL.
In your case, I would personally set up the entire URL string as a stringWithFormat:
NSString *urlString = [NSString stringWithFormat:#"http://www.starturl.com/%#%#%#", whatToSearch, middleOfURL, resultsStr];
Insert the values you want into the URL that way by setting up whatToSearch, etc., to the values you want. This way, you don't have to worry about appending everything together
Your code should look like this:
NSString *urlString = [NSString stringWithFormat:#"http://starturl.com/?q=%#&max-results=%f", whatToSearch, [slider floatValue]];
EDIT: Corrected my answer. For UISlider it should be value property. For NSSlider you should use - floatValue method

Objective C unable to update UILabel more than once

I have a method which I created that appends some new text to a UILabel. I've tried two ways of doing this (one is commented out) but both of them only update the label the first time. Any more calls to this method do not update the label.
- (void) updateLog: (NSString*) text
{
/*
NSMutableString *newText = [logLabel.text mutableCopy];
[newText appendString: text];
logLabel.text = newText;
*/
logLabel.text = [logLabel.text stringByAppendingFormat:#"%#", text];
}
I am calling the method like this (the method is in the viewController):
[viewController updateLog: #"\nStarting...\n"]; // Works
[viewController updateLog: #"Test\n"]; // Does not work
I have searched everywhere for an answer, what am I missing? Thanks!
UILabel, unless set up otherwise, only displays a single line of text.
Change the numberOfLines property if you want more.
I actually figured this out. Turns out the string WAS being successfully updated, but the label size was too small, so the text was hidden.