label not updating in setter - iphone

ok so this problem is kinda weird because the NSLog I have right in front of the line of code that should be printing out the text is returning the correct value.
Here's the code:
-(void)setCurrentDate:(UILabel *)currentDate
{
NSInteger onDay = 1; //because if it's today, you are on day one, not zero... no such thing as a day zero
//get the nubmer of days left
if( [[NSUserDefaults standardUserDefaults] objectForKey:#"StartDate"] ){ //if there is something at the userdefaults
onDay = [self daysToDate:[NSDate date]];
}//otherwise, onDay will just be one
self.theCurrentNumberOfDaysSinceStart = onDay;
NSLog(#"On day: %d", onDay); //this is returning the correct values....
//print it out on the label
[currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];//echoes out the current day number
}
So when the app first launches, everything is fine. The label updates and everything. The problem arises when I hit a button that basically grabs a new date. In the process, it runs this:
//need to reload the "on day" label now
[self setCurrentDate:self.currentDate];
//and the "days left" label
[self setDaysLeft:self.daysLeft];
Again, I'm thinking this should all be correct because the NSLog is returning the correct stuff. I'm thinking that the problem is with the last line in the first block of code I showed... the line with the setText.
thanks for all your help!
cheers,
Matt

If you used a nib
When the nib loads and establishes all of it connections it... (From the Resource Programming guide)
looks for a method of the form set OutletName: and calls it if such a method is present
Therefore the nib will load and call setCurrentDate: passing in the unarchived UILabel as the parameter
In your method you configure the UILabel using the local reference passed into the method
[currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];
You at no point actually store a reference to this UILabel in an ivar, so technically you have leaked the label and as you have not set the ivar currentDate it will be initialised to nil. This is the danger of overriding a setter with an incorrect implementation.
At some point in your method you should be setting your ivar to the passed in variable. A normal setter would look like this
- (void)setCurrentDate:(UILabel *)currentDate;
{
if (_currentDate != currentDate) {
[_currentDate release];
_currentDate = [currentDate retain];
}
}
But
In your example I would not worry about this at all I would instead change this
//need to reload the "on day" label now
[self setCurrentDate:self.currentDate];
to something like
[self updateCurrentDate];
The implementation would look something like:
- (void)updateCurrentDate;
{
NSInteger onDay = 1;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"StartDate"]) {
onDay = [self daysToDate:[NSDate date]];
}
self.theCurrentNumberOfDaysSinceStart = onDay;
[self.currentDate setText:[NSString stringWithFormat:#"On day: %d", onDay]];
}

Related

Can't Select today's date on uidatepicker ( already pre-selected)

I added a UIDatePicker in my IOS app which get loaded by default with today's date selected.
I'm listening to the selected event to update my field but as today's is already selected I never get it today is the date I want to selec( because it is already selected). I need to change at least one of the column to soemthing different , and in a second step select back today's date.
Anyway to display the datepicker without a selected day or somehow listeng to the tab on the picker instead of the selection ?
Wouldn't like to add a Todays button in the toolbar on adding any external control to solve this, or start with a different day pre-selected as it iwll be the same issue with the pre-selected date.
Thanks
I am not 100% sure whether you are looking for this or not. But this works fine for me.
in the viewcontroller.m
- (void)viewDidLoad
{
[super viewDidLoad];
dp.date = [NSDate date]; //dp is datepicker object
NSDateFormatter *formDay = [[NSDateFormatter alloc] init];
[formDay setDateFormat:#"dd/MM/yyy HH:mm"];
NSString *day = [formDay stringFromDate:[dp date]];
txt.text = day;
}
-(IBAction)datepick:(id)sender
{
NSDateFormatter *formDay = [[NSDateFormatter alloc] init];
[formDay setDateFormat:#"dd/MM/yyy HH:mm"];
NSString *day = [formDay stringFromDate:[dp date]];
txt.text = day;
}
connect the method to value changed event of date picker and include UITextFieldDelegate
when the view is loaded,
when the date picker is rolled
Apple did not implement any notifications for this. The reason being is that the user will tap, spin, and change the date picker until they find the date they want. Then they would hit some sort of done or next button. You would not want the user to be trying to select a date and the picker keep dismissing. If you really want to implement this then you can subclass UIDatePicker or and capture touches on the section you want.
Try subclassing UIDatePicker, & overriding hitTest:withEvent:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// intercept the user touching the initially presented date on a datePicker,
// as this will normally not send an event.
// here we check if the user has touched the middle section of the picker,
// then send the UIControlEventValueChanged action
CGFloat midY = CGRectGetMidY(self.bounds);
CGFloat dY = fabs(midY - point.y);
if (dY < 17.0) // the active section is around 36px high
{
NSSet *targets = self.allTargets;
for (id target in targets)
{
NSArray *actions = [self actionsForTarget:target forControlEvent:UIControlEventValueChanged];
for (NSString *action in actions)
{
// suppress the leak warning here as we're not returning anything anyway
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[target performSelector:NSSelectorFromString(action) withObject:self];
}
}
}
return [super hitTest:point withEvent:event];
}
I'm sure it could be improved, but as a starting point it might help you.

Detect string or integer in Core Data

I have built in some Core Data support into my app from the Core Data Books example. The example uses Dates and Strings. However I have tried adding the ability to add and edit an Integer value.
//If the value is a string
if ([[editedObject valueForKey:editedFieldKey] isKindOfClass:[NSString class]]) {
textField.hidden = NO;
datePicker.hidden = YES;
textField.text = [editedObject valueForKey:editedFieldKey];
textField.placeholder = self.title;
[textField becomeFirstResponder];
}
//If the value is a number
else {
textField.hidden = NO;
datePicker.hidden = YES;
textField.text = [[editedObject valueForKey:editedFieldKey] stringValue];
textField.placeholder = self.title;
[textField becomeFirstResponder];
}
The first if statement is the in example code (without the check if its a string, I added that) and I added the else statement to run when its not a string but an integer. It works, however now when I edit a string it skips the if statement, so the line: if ([[editedObject valueForKey:editedFieldKey] isKindOfClass:[NSString class]]) isn't working somehow.
If you do look at the CoreDataBooks example from Apple, my code is the same, only I added a field which takes an Integer 16.
Edit
When putting a breakpoint on the first if statement and returning po [editedObject valueForKey:EditedFiledKey] in the console I get: Can't print the description of a NIL object.
I assume this is because it's before the object is made? This happens when the view appears (the view to enter a new string).
It's upon pressing the save button that this code is run:
- (IBAction)save {
// Set the action name for the undo operation.
NSUndoManager * undoManager = [[editedObject managedObjectContext] undoManager];
[undoManager setActionName:[NSString stringWithFormat:#"%#", editedFieldName]];
// Pass current value to the edited object, then pop.
if ([[editedObject valueForKey:editedFieldKey] isKindOfClass:[NSString class]]) {
[editedObject setValue:textField.text forKey:editedFieldKey];
}
else {
[editedObject setValue:[NSNumber numberWithInteger:[[textField text] integerValue]] forKey:editedFieldKey];
}
[self.navigationController popViewControllerAnimated:YES];
}
When this runs, its skips the first if statement and runes the else statement, then crashing and showing the error: Unacceptable type of value for attribute: property = "firstName"; desired type = NSString; given type = __NSCFNumber; value = 0.
firstName is the string attribute in my data model. Im guessing because that first if statement fails, its goes forward an expects an integer? Im really unsure.
OK, so based on the value being nil in the debugger, let me explain what's happening. In Objective-C, any message sent to nil object will simply do nothing, and then return nil (which happens to have exactly the same memory value as 0 and false and NO).
So you're doing this:
if ([[editedObject valueForKey:editedFieldKey] isKindOfClass:[NSString class]]) {
If editedObject is nil, then valueForKey will do nothing and return nil. Then you're sending isKindOfClass to nil which will also do nothing and return nil. Inside an if statement, nil will evaluate to NO, sending you to the else statement.
Where you do this:
textField.text = [[editedObject valueForKey:editedFieldKey] stringValue];
editedObject is nil, cascading to stringValue returning nil, and therefore you are trying to set the text field's value to nil, which is invalid and will crash your app.
The solution is to restructure your code to check for nil. Here's how I would write your code:
// don't do anything for a nil value note this will detect editedObject being nil, or the result of valueForKey: being nil.
if (![editedObject valueForKey:editedFieldKey]) {
return;
}
// figure out the string value
NSString *textFieldValue = [editedObject valueForKey:editedFieldKey];
if ([textFieldValue isKindOfClass:[NSNumber class]]) {
textFieldValue = [(NSNumber *)textFieldValue stringValue]
}
// update the text field
textField.hidden = NO;
datePicker.hidden = YES;
textField.text = textFieldValue;
textField.placeholder = self.title;
[textField becomeFirstResponder];
I tackled the same problem with more Core Data app. I also adapted the Core Data Books app. If you notice, in the original app, they use a BOOL variable (editingDate) to decide whether to show the date picker or not. I created a second BOOL variable, ('editingTextView`) and just change those BOOL variables depending on what needs to be edited. It may not be the most efficient way, but it is easy to program, and easy to follow what is already there in Core Data Books.

Couple Obj C issues including an error

So basically in this code I placed below there is a couple things I would like to accomplish. 1) In that first one I would like the Text Field to close after done is pressed, but it is not doing so. (Found that code on other forums). 2)On that first button when it is pressed down I would like it to send a time to be saved for when the button is released. 3) On release of that button I would like it to calculate the time between the two times along with some other calculations later.
Problem that I am mainly getting here is the error from the NSTimeInterval. It keeps telling me that NSTimeInterval is incompatiable with type NSTimeInterval. So a double is incompatible with a double??? (I have also tried it with NSTimeInterval *timePassed in the .h and just trying to set timePassed = to it and it doesn't work either. Similar error happens.
#import "MphViewController.h"
#implementation MphViewController
#synthesize speed, distance;
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(IBAction)triggerDown:(id)sender{
timeStart = [NSDate date];
}
-(IBAction)triggerUp:(id)sender{
NSInteger *dist;
NSString *display;
NSTimeInterval *timePassed = [timeStart timeIntervalSinceNow];
if ([distance.text length]== 0) {
display = #"Please enter a distance";
}
else{
dist = atoi(distance.text);
display = [[NSString alloc] initWithFormat:#"%d MPH",dist];
}
speed.text = display;
[display release];
}
Also if you have a chance to glance at the else statement. I'm not sure if that will work (seeing is after I enter a distance I still cant get rid of the numberpad). Id like to pass mph once it is calculated into that to be displayed on the screen. Very confused with how parsing is done on obj c. Anyways thanks for any and all help.
As for the textField part. My textField that it is assigned to is distance. Should that Bool be written differently to have distance in it or is that just the way it is supposed to be written?
You are denoting primitive types as pointers where they do not need to be. Remove the star (*) from the NSInteger and NSTimerIntervaldeclaration. The if check looks fine but instead of atoi just use:
dist = [distance.text integerValue];
Edit:
Notice a couple of memory management issues.
1 . Make sure you properly retain/release the date then later release it in dealloc.
-(IBAction)triggerDown:(id)sender{
[timeStart release];
timeStart = [[NSDate alloc] init];
}
2 . Your if statement will result in trying to release an NSString literal which likely will not crash but is incorrect memory management. Just use an autoreleased string and remove the [display release];
...
else{
dist = [distance.text integerValue];
display = [NSString stringWithFormat:#"%d MPH",dist];
}
speed.text = display;
}

Issue with transferring and editing integer info stored in coredata

I'm looking for some help. I've tried searching this site and have tried amending my code but I'm stuck. My issue is with displaying and editing an integer attribute stored in coredata. I have a detailview which uses a UITableView. It seems to display the integer correctly in the cell, using the following code:
cell.textLabel.text = #"Set target";
cell.detailTextLabel.text = [match.set_target stringValue];
but, when I try and edit the value by passing it to a UITextField on an editing view, it displays the integer incorrectly (for example 3 is displayed as 53916). I'm passing the value to the UITextField with this code: (note, editedObject is NSManagedObject, numField is UITextField, editedFieldKey is NSString).
[numField setText:[NSString stringWithFormat:#"%d", editedFieldKey]];
The values are passed to the editing view from the detail view using this code:
controller.editedFieldKey = #"set_target";
controller.editedFieldName = NSLocalizedString(#"Number of sets to win", #"set_legs");
I can display, edit and save strings and dates but I can't figure out Integers. Any help would be appreciated.
EDIT 1
I have save and cancel buttons on my edit view. The save button invokes:
- (IBAction)save {
// Set the action name for the undo operation.
NSUndoManager * undoManager = [[editedObject managedObjectContext] undoManager];
[undoManager setActionName:[NSString stringWithFormat:#"%#", editedFieldName]];
if (editingDate) {
[editedObject setValue:dateField.date forKey:editedFieldKey];
}
else if (editingNum) {
[editedObject setValue: [NSNumber numberWithInteger: [numField.text integerValue]] forKey: editedFieldKey];
}
else {
[editedObject setValue: textField.text forKey:editedFieldKey];
}
[self.navigationController popViewControllerAnimated:YES];
}
With the code for displaying the integer set as:
[numField setText:[NSString stringWithFormat:"%d", [editedObject valueForKey:editedFieldKey]]];
I have a warning about the line: Passing argument 1 of 'StringwithFormat' from incompatible pointer type.
On running it crashes with: +[NSString WithFormat:]: unrecognized selector sent to class 0x211d60'
You are passing a string to numberWithInteger, when instead you want the integer value from the string. Try changing it to this:
[editedObject setValue: [NSNumber numberWithInteger: [numField.text integerValue]] forKey: editedFieldKey]; .
"editedFieldKey is NSString"
[numField setText:[NSString stringWithFormat:#"%d", editedFieldKey]];
replace the formatter with %#
[numField setText:[NSString stringWithFormat:#"%#", editedFieldKey]];
EDIT:
Since you are not adding anything to the string, the stringWithFormat: message is unnecessary.
The following will product the same result.
[numField setText:editedFieldKey];
And for those who prefer '.' syntax for property accessors
numField.text = editedFieldKey;
EDIT 2
I will assume that you are passing in your managed object and context to the editing controller...
To display the value of the "set_target" attribute of your managed object.
[numField setText:[[editedObject valueForKey:editedFieldKey] stringValue]]; // set_target is returned as an NSNumber

Accessing a UITextField from an array in Objective-C

I have 4 UITextFields that I'm dynamically creating, in the viewDidLoad, which works good. I want to reference those objects when the UISlider value changes. Right now I'm storing those objects in a NSMutableArray and accessing them like so from the sliderChanged method:
NSInteger labelIndex = [newText intValue];
labelIndex--;
NSUInteger firstValue = (int)0;
NSMutableArray *holeArray = [pointsArray objectAtIndex:labelIndex];
UITextField *textField = [textFieldArray objectAtIndex:firstValue];
NSString *newLabel1Text = [[NSString alloc] initWithString:[[holeArray objectAtIndex:firstValue] stringValue]];
[textField setText: newLabel1Text];
[newLabel1Text release];
Everything is working good, but the program crashes on the setText: method. The last message I get from the program is: [UILabel drawTextInRect:] and then I get a EXC_BAD_ACCESS failure.
I want to be able to acces that dynamically created UITextField, but I must be going about it the wrong way.
Thanks!
Uh, yea, you create a text field, but you aren't displaying the field itself, just creating it.
If you want to do what I think you want to do, I would just do if statements.
ex.
if (firstValue == 1)
{
fieldone.text = #"whatever";
}
else if (firstValue == 2)
{
fieldtwo.text = #"whatever";
}