app crashes when I change the time on a date picker - iphone

I made an app with a textview that when you tap it, a date picker comes up. Is it something wrong with my code?
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(112, 88, 97, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[self.view addSubview:textField];
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker addTarget:self action:#selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];
[textField setInputView:datePicker];
I am getting the error 2013-08-04 20:38:54.249 Habit Pal[7252:c07] -[SleepModeViewController datePickerValueChanged:]: unrecognized selector sent to instance 0x8840d70

You need to add a "datePickerValueChanged:" method to your SleepMoveViewController.h & .m file.
If you don't have one, then you should create one.
And if you have one, check to make certain it's the right API signature. For example:
- (void) datePickerValueChanged: (id) sender;

As you know you dont have a value for -(void)datePickerValueChanged, You can put this anywhere below in the file.
Basically you would create something like this:
-(void)datePickerValueChanged:(id)sender{
//Put what you want to occur whan the value changes
}

Add this method in your SleepModeViewController
-(void) datePickerValueChanged:(UIDatePicker*) datePicker {
//write your code here
}

Related

Programmatically instantiating a Delegate to a component

I have an app which has a controller which already handles UITextFieldDelegate for textfields, now I want to add a second controller + UITextField programmatically which is separately from the main controller but is called from it.
So I have a MainController which handles input (that is working), then next to that, I defined this:
#interface TestUIDelegate : UIViewController <UITextFieldDelegate>{
TestUIDelegate has a property textField.
TestUIDelegate has a method:
- (void)initGUI:(UIView *)myView;
which initialises a textField like thus:
- (void)initGUI:(UIView *)myView {
self.view = myView;
textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15];
textField.placeholder = #"enter text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDone;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.delegate = self;
[self.view addSubview:textField];
}
which also works; the field shows up and is editable, keyboard comes up and you can type stuff.
So far so good, but now I want to Done button to work so the keyboard is dismissed, so I added:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
NSLog(#"Here?");
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"Or here?");
}
To my TestUIDelegate (actually I added all delegate methods from TextUIFieldDelegate).
I instantiate the TestUIDelegate from the didFinishLaunchingWithOptions in the MainController like this:
TestUIDelegate *controller = [[TestUIDelegate alloc] init];
[controller initGUI:self.view];
TextField still shows up the delegate methods are never called, none of them. Now I imagine i'm doing something very weird and I have looked through all answers on SO and in Google slightly relating to this, but they all do it by implementing the delegates in the MainController which is exactly what I really do not want. And I need it programmatically; not (at all) with the gui builder.
Can anyone enlighten me please? I don't think i'm going to figure this out on my own.
You need to add textFieldShouldReturn to get the keyboard to dismiss:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
TextFieldDidEndEditing will then be called as well, but you need to resignFirstResponder before that happens.
I found out what the problem was (but not why...); I was using
[controller initGUI:self.view];
changing that to:
[controller initGUI:self.window.rootViewController.view];
makes it work. I don't know why.
For people who are interesting to do this same thing (like I said; I couldn't find even one example on the web), here is the simplified project; https://dl.dropboxusercontent.com/u/6134596/TestDelegate.zip

Trying to implement Done/Cancel buttons on number keypad, but error is given when textfield is selected in simulator

I have a textfield which is number only. I'm trying to implement a done/cancel buttons on the keypad to get rid of the keypad.
In the simulator when I select the textfield to enter an amount I get the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-
[durood keyboardWillShow:]: unrecognized selector sent to instance 0x7644900'
*** First throw call stack:
(0x1c93012 0x10d0e7e 0x1d1e4bd 0x1c82bbc 0x1c8294e 0xb914f9 0x1ced0c5 0x1c47efa 0xac5bb2
0x3c5777 0x3be929 0x3c08a2 0x3c0931 0x3c097b 0x3ba117 0x123386 0x122e29 0x2e63c3 0x2e8442
0x2df85a 0x2de99b 0x2e00df 0x2e2d2d 0x2e2cac 0x2daa28 0x47972 0x47e53 0x25d4a 0x17698
0x1beedf9 0x1beead0 0x1c08bf5 0x1c08962 0x1c39bb6 0x1c38f44 0x1c38e1b 0x1bed7e3 0x1bed668
0x14ffc 0x209d 0x1fc5 0x1)
libc++abi.dylib: terminate called throwing an exception
Here is the code in my h file:
#import <UIKit/UIKit.h>
int dcounter;
int total;
int enteramount;
#interface durood : UIViewController {
IBOutlet UILabel *dcount;
IBOutlet UILabel *dtotal;
IBOutlet UITextField *numberTextField;
Here is the code in my m file for the extra buttons to be added to the keypad:
[super viewDidLoad];
UIToolbar *numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Cancel"
style:UIBarButtonItemStyleBordered target:self action:#selector(cancelNumberPad)],
[[UIBarButtonItem
alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Apply"
style:UIBarButtonItemStyleDone target:self action:#selector(doneWithNumberPad)],
nil];
[numberToolbar sizeToFit];
numberTextField.inputAccessoryView = numberToolbar;
}
-(void)cancelNumberPad{
[numberTextField resignFirstResponder];
numberTextField.text = #"";
}
-(void)doneWithNumberPad{
NSString *numberFromTheKeyboard = numberTextField.text;
[numberTextField resignFirstResponder];
}
What am I missing? Any help would be greatly appreciated. The keypad should look like this:
The crash is coming from the fact that durood does not have a method implementation for keyboardWillShow:.
Are you subscribing for notifications, like UIKeyboardWillShowNotification? You likely added a #selector(keyboardWillShow), but didn't actually create the method implementation.

UIDatePicker in iPhone

I'm struggling with UIDatePicker. I thought I could add it to my current view just as I would an ordinary subview, but it didn't appear. After some searching, I found documentation for putting it in a popover. I followed those instructions and got it to work on the iPad. But popovers don't work on the iPhone. What do I need to do to make it work there? Why can't I simply add it like a regular subview?
Here's my iPad code:
-(void)selectADate: (CGPoint)p
{
UIViewController* popoverContent = [[UIViewController alloc] init]; //ViewController
UIView *popoverView = [[UIView alloc] init]; //view
popoverView.backgroundColor = [UIColor blackColor];
UIDatePicker *datePicker=[[UIDatePicker alloc]init];//Date picker
datePicker.frame=CGRectMake(0,44,320, 216);
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker setTag:10];
datePicker.date = self.displayedDate;
[datePicker addTarget:self action:#selector(pickerChanged:) forControlEvents:UIControlEventValueChanged];
[popoverView addSubview:datePicker];
popoverContent.view = popoverView;
UIPopoverController * popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
//popoverController.delegate=self;
self.datePopover = popoverController;
[popoverController setPopoverContentSize:CGSizeMake(320, 264) animated:NO];
CGRect popoverLocation = CGRectMake(p.x-160, p.y-200, 320, 216);
[popoverController presentPopoverFromRect:popoverLocation inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];//tempButton.frame where you need you can put that frame//
}
- (void)pickerChanged:(id)sender
{
self.displayedDate = [sender date];
[self showMonthContainingDate:[sender date]];
}
My screen is currently laid out as a sort of calendar page showing a month of days. Each day's sell is a subview. At the top of the screen is a header, which has information on the year, month, etc. When the user taps the header, the date picker appears, and the calendar page displays the month selected that corresponds to the date chosen in the picker with the day highlighted (that day's subview's background has a different color).
I'm not sure why I even need a popover, unless it is just to provide a blank view on which to place the date picker that is in front of the tiled views of my calendar page. But then shouldn't I be able to simply add it as a subview and then call bringSubviewToFront:? I tried that, but it didn't work on the iPad, hence my use of the popover.
I can get it to display if I add it when I add the other subviews, but I want it to display when I tap the heading. Here's my tap code:
- (IBAction)tap:(UITapGestureRecognizer *)sender {
//tap gesture recognizer
//Assume the user tapped on a day cell.
for (UIView *dayCell in self.view.subviews) {
if (CGRectContainsPoint(dayCell.frame, [sender locationInView:self.view])) {
//found the cell that was touched.
//NSLog(#"Found a view containing the touch with coords. %#",NSStringFromCGRect(dayCell.frame));
for (UIView *insideView in dayCell.subviews) {
for (UILabel *dayElement in insideView.subviews) {
//found a subview of the day cell.
if ([dayElement isKindOfClass:[UILabel class]]) {
NSLog(#"Found a subview %#",dayElement.text);
}
}
}
}
if ([dayCell isKindOfClass:[UILabel class]]) {
// This is the heading label.
UILabel * headingLabel = (UILabel *) dayCell;
if (CGRectContainsPoint(headingLabel.frame, [sender locationInView:self.view])) {
NSLog(#"The heading was tapped");
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
//iPhone code goes here
[self iphoneSelectADate:[sender locationInView:self.view]];
} else {
[self selectADate:[sender locationInView:self.view]];
}
}
}
}
}
Here is the currently nonworking iPhone code:
-(void)iphoneSelectADate: (CGPoint)p
{
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height - 216, 320, 216)];
[datePicker setDate:[NSDate date]]; //This is the default
[datePicker setHidden:NO];
[self.view addSubview:datePicker];
}
If I step through in the debugger, I see this code is executed, but the datepicker does not display.
UIDatePicker inherits from UIView, so you can add it just like a UILabel. Make sure you give it a frame.
Something like this would work for the bottom of an iPhone screen:
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height - 216, 320, 216)];
[datePicker setDate:[NSDate date]]; //This is the default
[self.view addSubview:datePicker];
It sounds like you likely have a subview layering issue, not a UIDatePicker issue though.
If that doesn't work, post some of your code and we'll help figure it out.
Not sure if this will help, but UI changes for views that are already present require to be dispatched using the main_queue
for e.g.
dispatch_async(dispatch_get_main_queue(), ^
{
[self.view addSubview:yourSubview];
});
I think I may have found the key to my problem. After reading through this document on the various places to place orientation-related code, I decided on viewWillLayoutSubviews. I read through the document again and decided to try putting that code in viewWillAppear instead, and that seems to have resolved the problem.
The change to using viewWillAppear also required implementation of willAnimateRotationToInterfaceOrientation:duration:
It looks like viewWIllLayoutSubviews is needed for iPad but not iPhone, so I've also added this:
-(void)viewWillLayoutSubviews
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
//iPhone code goes here (empty, since calling showMonthContainingDate: doesn't work from here in iPhone
} else {
//ipad code goes here
NSDate *dayToDisplay = self.displayedDate;
[self showMonthContainingDate:dayToDisplay];
//iPad uses wrong dimensions unless the routine is called from here.
}
}
One final note. There is one scenario where the orientation of the device is not set correctly -- that is landscape on an iPhone at launch. According to this answer to another question the iPhone always launches in portrait unless it is a landscape-only app.

how do I tell which UITextField just triggered the textFieldShouldReturn callback?

I have mulitple UITextFields in a view.
I'm assuming the place to capture the vlue of a UITextField once the user comes out of it is to implement the delegate method "textFieldShouldReturn".
Question - In "textFieldShouldReturn" however, how do I tell which of the UITextField's triggered this?
For example assuming at this stage I now need to update my data model with the value of what the UITextField now shows, so need to update the correct field in the model with aligns with that particular UITextField.
PS If there's a better approach, or a way to kind of "binding" approach I'm missing I'd be interested
...or you can skip all the tags and make your UITextViews instance vars and do:
- (void)viewDidLoad {
myTextView1 = [[UITextView alloc] init];
myTextView2 = [[UITextView alloc] init];
myTextView3 = [[UITextView alloc] init];
myTextView4 = [[UITextView alloc] init];
......
}
- (void)textFieldShouldReturn:(UITextField *)textField {
BOOL shouldReturn = NO;
if (textField == myTextView1)
{
shouldReturn = YES;
}
...and so on...
}
... release the instance vars in the dealloc...
I kinda prefer this way, but the other answer will work too.

Having Trouble With UITextField and NSString

I have the following code for UITextField. The problem I'm having is that the text does not persist. For example, when I present a modal view, then dismiss it, the UITextField does not have the text anymore in it. I want the text to remain there until I dimiss that view with the text field.
I am displaying the UITextField like this:
UITextField *nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
nameTextField.delegate = self;
[nameTextField addTarget:self action:#selector(editingEnded) forControlEvents:UIControlEventEditingDidEnd];
[nameTextField setEnabled: YES];
self.myTextField = nameTextField;
[nameTextField release];
Then I have:
- (void)editingEnded
{
NSString *tempRoutineName = self.myTextField.text;
self.routineName = tempRoutineName;
[tempRoutineName release];
}
Instead of editingEnded, Implement the UITextFieldDelegate protocol. Go to the textFieldDidEndEditing method and reassign the value of text in it.
Like,
-(void) textFieldDidEndEditing:(UITextField *)textField{
if (textField.tag ==0){
self.myTextField = textField;
// myTextField is a property
}
Now in the in the viewDidLoad method or the viewWillAppear method, go ahead and assign this value back to the textField.
If necessary use [tableView reloadData] if this is used in a tableView or use [self reloadInputViews] (if necessary).
Then again, its all logical. Nothing too complex in code.
Use UITextFieldDelegate method that is textFieldDidEndEditing, which gets called when editing ends
In my opinion:
NSString *tempRoutineName = self.myTextField.text;
self.routineName = tempRoutineName;
[tempRoutineName release];
You haven't own tempRoutineName to release. Comment out the release and check.