Objective C: How to use addTarget:action:forControlEvents: method? - objective-c

I am trying to update the date and time displayed in a table cell immediately after the UIPicker's data has changed (real time updated). I implemented the following code. My "update" method is not being called despite changing the values in the picker. Can anyone advise? Thanks!
Zhen
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if (row == 0)
{
self.picker.hidden = NO;
[self.picker addTarget:self action:#selector(updateDate) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void)updateDate
{
selectedDate = [self.picker date];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"dd-MM-yyyy HH:mm"];
selectedDateString = [formatter stringFromDate:selectedDate];
[tableView reloadData];
}

You need to put a colon after the selector name.
[self.picker addTarget:self action:#selector(updateDate:) forControlEvents:UIControlEventTouchUpInside];
Also, the updateDate method should take an object of type id.
- (void) updateDate:(id) obj { }

change in your code -
[self.picker addTarget:self action:#selector(updateDate:) forControlEvents:UIControlEventTouchUpInside];
to
[self.picker addTarget:self action:#selector(updateDate:) forControlEvents:UIControlEventAllEvents];
you can also handle it in UIPicker delegates.

Related

NSIndexPath only retrieves first cell value

I'm trying to print out the value of where the user clicked in a method that is called when a user updates the value of a UISwitch in some of the cells. There are four cells that have the UISwitch set as an accessory of the cell. I already have the infrastructure in place to check against the values of calling [self.basicObjects objectAtIndex:indexPath.row], but the problem is, that no matter which cell I press, the 0 value of the NSMutableArray that contains the titles of the four cells is called.
- (void)switchChanged:(id)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"self.basicObjects value: %#", [self.basicObjects objectAtIndex:indexPath.row]);
}
As a side note, as I was looking at similar questions, it also seemed important to note that self.settingsTable is a grouped UITableView with these four cells being in section 1 (0, 1, 2). The other two sections do not contain any UISwitch as an accessory type, it's only this section, and only this one the references the switchChanged:cellForRowAtIndexPath: method.
Edit - 7:31pm
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17.5];
if (indexPath.section == 0)
{
// change the text to standard case
// change text color
}
else if (indexPath.section == 1)
{
cell.textLabel.text = [self.basicObjects objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
self.switchProperty = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = self.switchProperty;
if ([[self.basicStatus objectAtIndex:indexPath.row] isEqual:#"YES"])
{
[self.switchProperty setOn:YES animated:YES];
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
}
else if ([[self.basicStatus objectAtIndex:indexPath.row] isEqual:#"NO"])
{
[self.switchProperty setOn:NO animated:YES];
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
}
}
else if (indexPath.section == 2)
{
cell.textLabel.text = [self.objects objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [self.objectsType objectAtIndex:indexPath.row];
cell.detailTextLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17.5];
if ([[self.objectsStatus objectAtIndex:indexPath.row] isEqual:#"Setup"])
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.298 green:0.851 blue:0.392 alpha:1]; // #4CD964 (green)
else if ([[self.objectsStatus objectAtIndex:indexPath.row] isEqual:#"Not Setup"])
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.898 green:0.267 blue:0.267 alpha:1]; // #E54444 (red)
}
return cell;
}
You can't pass the indexPath in your action method that way. You can only pass the sender, and optionally, the event that triggered the action. You need to get the indexPath a different way. One common way is to give the switch a tag that's equal to the indexPath.row, and use that tag as an index into your array.
Here's a problem. You can't send the second parameter like this.
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
I recommend that you set a tag and use it like as below.
[self.switchProperty setTag:indexPath.row];
[self.switchProperty addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
and in switchChanged: will be...
- (void)switchChanged:(id)sender
{
NSLog(#"self.basicObjects value: %#", [self.basicObjects objectAtIndex:[sender tag]]);
}

Highlight UITableViewCell while pickerview event

I have a UI which contains a UITableView and a UIDatePicker. When I select a Row on my table it is highlighted, but as soon as I interact with the DatePicker (scroll to a new value) the row isn't highlighted anymore. The value of the row is bound to that of the DatePicker. How can I permanently highlight the cell?
In the iCal-App -> Add -> Start&End I saw this behaviour.
I tried the selectRowAtIndex method in my ValueChanged-method of the picker. I thought that the highlighting is lost in this callback-method.
-(IBAction)setStartTimeMethod
{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE, dd. MMM yyyy HH:mm"];
if(!self.endDateRowSelected)
self.date = [dateFormat stringFromDate:[datePicker date]];
else
self.endDate = [dateFormat stringFromDate:[datePicker date]];
[dateFormat release];
// [self.tableView1 selectRowAtIndexPath:tableView1.indexPathForSelectedRow animated:NO scrollPosition:UITableViewScrollPositionTop];
[self.tableView1 reloadData];
}
Edit, my didSelectRowMethod
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"EEE, dd. MMM yyyy HH:mm"];
if(indexPath.row == 0){
NSLog(#"Start");
self.endDateRowSelected = NO;
NSDate *startDate = [formatter dateFromString:self.date];
[datePicker setDate:startDate animated:YES];
//if(self.endDateRowSelected)
// [tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
}else if(indexPath.row == 2){
NSLog(#"End");
self.endDateRowSelected = YES;
if(self.endDate){
NSDate *endDateTime = [formatter dateFromString:self.endDate];
[datePicker setDate:endDateTime animated:YES];
}
}else{
self.endDateRowSelected = NO;
}
[formatter release];
// Won't work, doesn't allow highlighting a cell.
// [tableView deselectRowAtIndexPath:indexPath animated:NO];
}
BR,
mybecks
Use this piece of code in the end of didSelectRowAtIndexPath delegate method of table view,
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Try:
[self.tableView1 reloadData];
// and then
[self.tableView1 selectRowAtIndexPath:tableView1.indexPathForSelectedRow animated:NO scrollPosition:UITableViewScrollPositionTop];
I guess a much better way of doing this is with IBOutlets for each custom cell in your table. If you are editing the date for that cell, then why reload the entire table? If you have less number of cells, you can go ahead and create custom UITableViewCell, add labels and update only those labels from your UIDatePicker delegate callbacks.
Use the following code in didSelectRowAtIndexPath
cell.selectionStyle=UITableViewCellSelectionStyleBlue;
The solution was quite easy.
In my cellForRowAtIndexPath I must call the selectRowAtIndexPath method.
...
if(indexPath.row == 0){
cell.description.text = [dict objectAtIndex:indexPath.row];
cell.dateTime.text = self.startDate;
if(!endDateRowSelected)
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}else if(indexPath.row == 2){
cell.description.text = [dict objectAtIndex:indexPath.row];
cell.dateTime.text = self.endDate;
if(endDateRowSelected)
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
...
The bool is set in my didSelectRowAtIndexPath, depending on clicking on Start or End.
I still reload the table in my pickerValueChanged delegate.
Thank you for time & help.

Realtime Values in UITableViewCell from UIDatePicker

I have a UIViewController with two UI Components: UITableView and UIDatePicker. My goal is, to create a screen like the ical->add->Start & End.
I added the the tableView delegate and dateSource to my header file. In the implementation file, I want to display the current value from the datePicker in my tableCell (like the iCal Start & End screen).
My .m looks like the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[datePicker addTarget:self action:#selector(datePickerValueChanged) forControlEvents:UIControlEventValueChanged];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSMutableArray *dict = [dictionary objectForKey:#"DATA"];
if(indexPath.row == 1){
UISwitch *switchSpecifyEnd = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = switchSpecifyEnd;
[(UISwitch *)cell.accessoryView setOn:NO]; // Or NO, obviously!
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(switchSpecifyEnd)
forControlEvents:UIControlEventValueChanged];
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
}else if(indexPath.row == 3){
UISwitch *switchOpenEnd = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = switchOpenEnd;
[(UISwitch *)cell.accessoryView setOn:NO]; // Or NO, obviously!
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(switchOpenEnd)
forControlEvents:UIControlEventValueChanged];
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
}else{
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
// NSLog(#"Update Cell: %#",<but how>);
}
return cell;
}
- (void)datePickerValueChanged{
NSLog(#"Logging: %#", [NSString stringWithFormat:#"%#",datePicker.date]);
}
How can I update my tableCell with the value from the datePicker?
BR,
mybecks
For updating your table cell you need to reload your table and when your table will reload then cellForRowAtIndexPath will get call and you can update your cell text.
Suppose this is your method that gets called when you select some date in date picker
-(IBAction)setStartTimeMethod
{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE MMM dd, yyyy hh:mm a"];
self.startTimeString = [dateFormat stringFromDate:[timeStartPicker date]];
[dateFormat release];
[optionsTableView reloadData];
}

How to display events in tableView sorted by NSDate?

I have an events app which gets events data from sqlite database and displays it in tableView. I also converted date from the sqlite table from NSString to NSDate.
Now I want to display records sorted by Date and also don't want to display event that is finished.
Here is my EventViewController.m
#import "EventViewController.h"
#implementation EventViewController
#synthesize events,eDate;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Events";
//Get the DBAccess object;
DBAccess *dbAccess = [[DBAccess alloc] init];
//Get event array from database
self.events = [dbAccess getAllEvents];
//Close the database
[dbAccess closeDatabase];
//Release dbAccess object to free its memory
[dbAccess release];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations.
return YES;
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"# of Sections");
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//NSLog(#"Countring Rows");
return [self.events count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Creating cell");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
event = [self.events objectAtIndex:[indexPath row]];
// Configure the cell.
cell.textLabel.text = event.name;
cell.detailTextLabel.text = event.location;
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Formate Date from string to NSDate
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyyMMdd"];
NSDate *eeDate = [dateFormatter dateFromString:event.date];
NSLog(#"%#", eeDate);
[dateFormatter setDateFormat:#"EEEE MMMM d, YYYY"];
eDate = [dateFormatter stringFromDate:eeDate];
NSLog(#"%#", eDate);
[dateFormatter release];
//Event *event;
if (tableView == self.tableView)
{
event = [self.events objectAtIndex:[indexPath row]];
//event = [[self.events objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
}
else
{
event = [self.events objectAtIndex:[indexPath row]];
}
EventDetailViewController *detailViewController = [[EventDetailViewController alloc]
initWithStyle:UITableViewStyleGrouped];
detailViewController.eventDetail = [events objectAtIndex:indexPath.row];
detailViewController.eventName = event.name;
detailViewController.eventLocation = event.location;
detailViewController.eventNote = event.note;
detailViewController.eventDate = eDate;
detailViewController.eventTime = event.time;
//Pust detail controller on to the stack
[self.navigationController pushViewController:(UITableViewController *)detailViewController animated:YES];
//release the view controller
[detailViewController release];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc
{
[events release];
[super dealloc];
}
#end
Please Help.
Since the date is represented as yyyyMMdd, we can use the usual string comparison to eliminate older events using the current date. Then we can sort the remaining events.
NSArray * allEvents = [dbAccess getAllEvents];
NSDateFormatter * dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"yyyyMMdd"];
NSString * todaysDateAsString = [dateFormatter stringFromDate:[NSDate date]];
NSArray * futureEvents = [allEvents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"date >= %#", todaysDateAsString]];
NSSortDescriptor * descriptor = [NSSortDescriptor descriptorWithKey:#"date" ascending:YES];
self.events = [futureEvents sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
You can use NSSortDescriptors to sort your events.
Suppose you have a property finished that indicates when the event is finished, you could filter the array like this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"finished = NO"];
self.events = [[dbAccess getAllEvents] filteredArrayUsingPredicate:predicate];
And than, if the event object has a date property that is the one you are trying to sort ascending, you could use NSSortDescriptor to sort it.
NSSortDescriptor *descriptor = [NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
NSArray *arrayDescriptors = [NSArray arrayWithObject: descriptor];
self.events = [self.events sortedArrayUsingDescriptors:arrayDescriptors];
[descriptor release];

How can I present a picker view just like the keyboard does?

I want a UIPickerView to show up when I press a button (just like keyboard) and then go away when user taps anywhere on the screen. How can I do this? Thanks.
A bit more background: I have a UITextField called months in UITableViewCell. Now the best option for me is to put a UIPikcerView there and it will be easier for the user to just chose the month rather than having to type it out (and it's the better way). But UIPickerView looks really ugly in a UITableViewCell, not to mention I can't change it's gigantic size. So what should I do in this case?
This is how you should use UIPickerView for a textField in a UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle= UITableViewCellSelectionStyleNone;
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.clearsOnBeginEditing = NO;
textField.textAlignment = UITextAlignmentRight;
textField.delegate = self;
[cell.contentView addSubview:textField];
//textField.returnKeyType = UIReturnKeyDone;
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
// if you want a UIPickerView for first row... then do the following //
// Here.. packSizePickerView is an object of UIPickerView
if (indexPath.row == 1)
{
textField.tag=0;
textField.delegate= self;
packSizePickerView.delegate = self;
packSizePickerView = [[UIPickerView alloc] init];
packSizePickerView.autoresizingMask=UIViewAutoresizingFlexibleWidth;
packSizePickerView.showsSelectionIndicator=YES;
textField.inputView = packSizePickerView;
}
// if you want to select date / months in row 2, go for UIDatePickerView //
if (indexPath.row == 1)
{
textField.tag = 1;
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker addTarget:self action:#selector(datePickerValueChangedd:) forControlEvents:UIControlEventValueChanged];
datePicker.tag = indexPath.row;
textField.delegate= self;
textField.inputView = datePicker;
[datePicker release];
}
}
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [myArray objectAtIndex:row];
return cell;
}
And for datePickerValueChangedd
- (void)datePickerValueChangedd:(UIDatePicker*) datePicker{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 68, 68)];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterMediumStyle;
label.text = [NSString stringWithFormat:#"%#",[df stringFromDate:datePicker.date]];
NSLog(#"I am inside the datePickerValueChanged - - %#", label.text);
[df release];
globalValue1 = label.text;
// use a global variable to copy the value from the pickerView. //
}
Now in the textFieldDidEndEditing:
-(void) textFieldDidEndEditing:(UITextField *)textField {
if (textField.tag ==0)
[textField setText: globalValue0];
if (textField.tag ==1)
[textField setText: globalValue1];
}
And to resign UIDatePicker, set the UIView as a UIControl and
resignFirstResponder
I think that you need to put your UIPickerView "outside" the viewable screen and animate it in when the button is pressed. I'm not really sure what the best way to get rid of it would be but you could probably listen for a tap on the parent view when the picker is visible and then animate it back out.