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.
Related
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
I'm making a little demo app and I'm having trouble changing.
Heres the thing:
I have a UIButton that every click will add a character in a NSString in a UITextField.
And I put an IBAction(Mudar_Resposta) on that UITextField(campo) in the part 'Value Changed'.
In that IBAction, I put that:
- (IBAction)MudarResposta:(id)sender {
campo.text=#"lol";
}
But I can't get it to work. Any ideas?
Thanks.
The proper way to get it to work is to connect an action method to the Touch Up Inside event for your button. Within that method, edit they text for your text field.
- (IBAction)mudarResponsta:(id)sender { // Connect to Touch Up Inside of your button
campo.text = [NSString stringWithFormat:%# %#", campo.text, #"lol"]; // Add string ' lol' every time it's called
}
Connecting to Value Changed will never invoke the method because the value is never being changed—you're connecting the changing method to the change…if that makes any sense.
Most likely you didn't connect that action to anything in the XIB file.
- (IBAction)Button:(id)sender {
[self.contacts addObject:_txtField.text];
_txtField.text=#"";
}
Here contacts is an Array name which is a Mutable Array. txtField is UITextField.
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
I've added the following image to help illustrate the problem better:
Hi,
I'm looking for the best starting point to alter the data stored my core data model directly - speaking as someone who's new to the area. From my reading I'm pretty confident I shouldn't touch my NSArrayController, which was my natural instinct, and that I should always tackle the model. This makes sense but because I've used bindings and core data, xcode has generated everything for me and I don't have a sense of building up a class from scratch myself.
For my initial task, I have a 'jobs' entity and NSArrayController. It has a jobTotalHours attribute that's a string in the 00:00:00 format and has a corresponding 'Hours' column for each job in an NSTableView. Separate to this, I have a stopwatch button that's linked to a text field next to it, displaying time as a 00:00:00 string. I have a class working that starts and stops a timer counting and displays it in increments of hours, minutes and seconds.
What I need to do is to make the timer add time onto the jobTotalHours attribute for the current job highlighted in the NSTableView. The separate textfield has now been bound to display the time of the current highlighted hours column so that part's taken care of. In other words, the timer was originally adding time to a test variable and displaying it in an autonomous text field for testing reasons. Now I need it to add time onto whatever job is highlighted in a table view and I need to access the model programmatically without being sure of what step to take first.
Thanks in advance for any advice. I'll include the timer class below if it's any use. I'm pretty sure it's rough and bad but it works:
timerController.h:
#import <Cocoa/Cocoa.h>
BOOL timerStarted;
int timerCount;
int timerSeconds;
int timerMinutes;
int timerHours;
NSString *timerString;
NSString *timerFieldSeconds;
NSString *timerFieldMinutes;
NSString *timerFieldHours;
#interface timerController : NSObject <NSApplicationDelegate> {
NSWindow *window;
NSTimer *timerNoOne;
IBOutlet NSCell *timerOneOutputLabel;
IBOutlet id timerClockField;
}
-(IBAction)toggleTimerClock:(id)sender;
#property (assign) IBOutlet NSWindow *window;
#end
timerController.m:
#import "timerController.h"
#implementation timerController
-(IBAction)toggleTimerClock:(id)sender
{
if (timerStarted==FALSE) {
timerStarted = TRUE;
} else {
timerStarted = FALSE;
}
}
#synthesize window;
- (void) awakeFromNib {
// clear timer
[timerClockField setStringValue:#"00:00:00"];
// initialize timer to count each second
timerNoOne = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(updateTimerNoOne:)
userInfo:nil
repeats:YES];
}
- (void) updateTimerNoOne:(NSTimer *) timer {
if (timerStarted==FALSE) {
// do nothing. Timer is switched off.
} else {
timerCount = timerCount + 1;
timerSeconds = fmod(timerCount, 60);
timerMinutes = floor(timerCount / 60);
timerHours = floor(timerCount / 3600);
if (timerSeconds < 10) { // add a leading 0 for formatting reasons.
timerFieldSeconds = [NSString stringWithFormat:#"0%d",timerSeconds];
} else {
timerFieldSeconds = [NSString stringWithFormat:#"%d",timerSeconds];
}
if (timerMinutes < 10) {
timerFieldMinutes = [NSString stringWithFormat:#"0%d",timerMinutes];
} else {
timerFieldMinutes = [NSString stringWithFormat:#"%d",timerMinutes];
}
if (timerHours < 10) {
timerFieldHours = [NSString stringWithFormat:#"0%d",timerHours];
} else {
timerFieldHours = [NSString stringWithFormat:#"%d",timerHours];
}
NSString *timerString = [NSString stringWithFormat:#"%#:%#:%#",timerFieldHours,timerFieldMinutes,timerFieldSeconds];
//[timerClockField setStringValue:timerString];
}
}
#end
Update:
From reading some more, I'm wondering if it's a better approach for me to update the string in the textcell itself on each second of timer change and then only commit changes to the model on the timer finishing (e.g. the clock was stopped). Previously I was thinking of saving the model's jobTotalHours string second by second as this was directly altering the model and avoiding controllers, which I thought was the advised route to take.
Update:
I had a subclass set up for NSTableView and NSArrayController. I was able to use them to detect selection changes to the rows in the table and print them out to the console. The subclass was called:
#interface modelUtilController : NSObject
Which performed the above tasks fine. I now wanted an outlet to the NSManagedObject so that I could directly manipulate assets in it while keeping outlets to the NSTableView to detect changed in row selection. I read that the subclass should be
#interface modelUtilController : NSManagedObject
which I changed it to and included an outlet to the data model. This crashes the original detection for changes in row selection, so I'm doing something wrong now. Perhaps I have to separate the subclass into 2?
Update : Possibly Complete
Ok I think I've solved this after 3 days at it. As far as I can see it's working but I haven't put it fully to work yet. Basically I created a separate function that I call from my timer once every second:
void amendTotalHours(id anObject)
This function uses my jobs NSArrayController and then finds the current value in the hours column using:
NSArray *selectedObjectsArray = [anObject selectedObjects];
NSManagedObjectModel *firstSelectedObject = [selectedObjectsArray objectAtIndex:0];
NSString *readCurrentTime = [firstSelectedObject valueForKey:#"jobTotalHours"];
I then convert the string of time formatted into 00:00:00 to an integer of the total seconds. I add one onto this for each call from the timer and then convert the seconds back into a string in the 00:00:00 format. Finally, I send this back to the NSArrayController using:
[firstSelectedObject setValue:[NSString stringWithFormat:#"%#", timeValue] forKey:#"jobTotalHours"];
And cry a (maybe temporary) sigh of relief.
Ok I think I've solved this after 3 days at it. As far as I can see it's working but I haven't put it fully to work yet. Basically I created a separate function that I call from my timer once every second:
void amendTotalHours(id anObject)
This function uses my jobs NSArrayController and then finds the current value in the hours column using:
NSArray *selectedObjectsArray = [anObject selectedObjects];
NSManagedObjectModel *firstSelectedObject = [selectedObjectsArray objectAtIndex:0];
NSString *readCurrentTime = [firstSelectedObject valueForKey:#"jobTotalHours"];
I then convert the string of time formatted into 00:00:00 to an integer of the total seconds. I add one onto this for each call from the timer and then convert the seconds back into a string in the 00:00:00 format. Finally, I send this back to the NSArrayController using:
[firstSelectedObject setValue:[NSString stringWithFormat:#"%#", timeValue] forKey:#"jobTotalHours"];
And cry a (maybe temporary) sigh of relief.
I am trying to learn cocoa and have a few problems with KVC and bindings. I have a nstableview with three columns; "checkbox", "text", "icon". The values of each column is binded to an arraycontroller using KVC. When program is launched the rows and columns are correctly filled into the tableview according to the values in the array. I can click a row and correctly print the content of that row using something like this:
- (IBAction)fileTableViewSelected:(id)sender{
NSInteger r;
NSDate *fModOne;
id object;
r = [[NSNumber numberWithInt:[sender selectedRow]] intValue];
object = [arrayIntersect objectAtIndex:r];
fModOne = [object valueForKey:#"fileModifiedDirOne"];
NSLog(#"Date found in row is %#",fModOne);
}
My problem is when I try to click the checkbox in column one and change the value of the box. Initially, the value of the checkbox is set to 1 using the arraycontroller which works fine, but when I want to change the value of the checkbox of a specific row to 0 by clicking on it the program crashes. When the box is clicked an action is correctly called and this is where I thought I could simply change the value of my objects BOOL by calling:
[object setValue:[NSNumber numberWithBool:NO] forKey:#"doSync"];
My setters and getters for the BOOL doSync is defined as:
#property(nonatomic, readwrite) BOOL doSync;
#dynamic doSync;
- (void)setDoSync:(BOOL) value{
NSLog(#"setting dosync %i", value);
doSync = NO;
}
- (BOOL)doSync{
return doSync;
}
I have searched everywhere for a solution to my problem, but I am unable to find any examples of how to use checkboxes in tableview using KVC and bindings. I appreciate any help I can get on this and I would appreciate any examples I could take a look at.
Cheers and thanks! Trond
You don't need to implement this yourself as an action. Just bind the column through your array controller's arrangedObjects to the doSync property of the model objects.
If you don't want to use Bindings, you still shouldn't implement it as an action. Instead, be the table view's data source and respond to the message the table view will send you to change one of the values.
#dynamic doSync;
There's no reason to have this if you turn around and implement the accessors for that property in the same class.
If this is a managed-object class and the property is an attribute of the entity, then your accessors should send [self willAccessValueforKey:] before and [self didAccessValueForKey:] after accessing the instance variable. If that's all they do, then you should not implement the custom accessors at all; cut them out and have #dynamic alone.
- (void)setDoSync:(BOOL) value{
doSync = NO;
That's not setting the property to the value passed in.