UIDatePicker in tableview can't be changed sometimes - ios

sometimes I have problems with the UIDatePicker. I built a screen with a UITableView where I can set a start time and an end time for each day of the week.
Now, however, I have the strange behavior that the picker sometimes does not allow a change. It is grayed out but not disabled. When I turn the picker it moves, but when I let go, it automatically returns to its previous value.
The behavior is reproducible. I change one day and close the picker. Change another day and close the picker. Then I scroll down a bit, the tableview jerking slightly. If I now open the last changed picker I have the mentioned behavior. I noticed the behavior on iOS 9 to 11 and on different devices.
For a better understanding, I have created a screenshot.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"timeProfilSettingsCell";
TimeProfilSettingsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDate *dateValidFrom = nil;
NSDate *dateValidUntil = nil;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
if (cell == nil)
{
[tableView registerNib:[UINib nibWithNibName:#"TimeProfilSettingsCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
TimeInterval *timeInterval = [nma_currentTimeInterval objectAtIndex:indexPath.row];
if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:#"IconHakenBlau"]];
}
else if (timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:#"Clock_blue"]];
}
else
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:#"IconOvalBlau"]];
}
cell.separatorView.backgroundColor = [UIColor colorWithRed:227.0/255.0 green:227.0/255.0 blue:227.0/255.0 alpha:1.0];
cell.weekDayLabel.text = [self getWeekDayName:indexPath.row];
[cell.checkBoxButton addTarget:self action:#selector(checkBoxButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.checkBoxButton setTag:indexPath.row];
cell.validityLabel.textColor = [UIColor colorWithRed:123.0/255.0 green:164.0/255.0 blue:219.0/255.0 alpha:1.0];
[cell.validityButton addTarget:self action:#selector(validityButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.validityButton setTag:indexPath.row];
// Handling so that the picker is closed when it is clicked elsewhere
UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissDatePicker:)];
tapGestureRecognize.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGestureRecognize];
BOOL b_open = NO;
if (b_pickerVisible && ni_touchedRow == indexPath.row)
{
b_open = YES;
cell.b_validityPickerVisible = YES;
[cell.validityStartPicker setHidden:NO];
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setHidden:NO];
[cell.validityEndPicker setEnabled:YES];
cell.validityFromLabel.hidden = NO;
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 304, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
[cell.validityStartPicker setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[cell.validityEndPicker setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[cell.validityStartPicker addTarget:self action:#selector(updateValidityStartPicker:) forControlEvents:UIControlEventValueChanged];
[cell.validityEndPicker addTarget:self action:#selector(updateValidityEndPicker:) forControlEvents:UIControlEventValueChanged];
if (b_pickerJustOpened)
{
b_pickerJustOpened = NO;
if (tableView.contentOffset.y > 0)
{
tableView.contentOffset = CGPointMake(0, tableView.contentOffset.y + 102);
}
}
if (b_pickerValueChanged)
{
// Picker-value not changed
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
// Default value, if the entry was previously "not"
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x20 /* 8:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x40 /* 16:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
b_pickerValueChanged = YES;
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else
{
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
}
}
else
{
cell.b_validityPickerVisible = NO;
cell.validityStartPicker.hidden = YES;
cell.validityEndPicker.hidden = YES;
cell.validityFromLabel.hidden = YES;
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setEnabled:YES];
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 88, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
}
if (b_pickerValueChanged && ni_touchedRow == indexPath.row)
{
if ([[dateFormatter stringFromDate:[cell.validityEndPicker date]] isEqualToString:#"00:00"])
{
cell.validityLabel.text = [NSString stringWithFormat:#"%# - 23:59:59 %# >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], NSLocalizedString(#"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:#"%# - %# %# >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], [dateFormatter stringFromDate:[cell.validityEndPicker date]], NSLocalizedString(#"oClock", nil)];
}
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else if ((timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1) || (ni_flagTimeIntervalActive == 0 && timeInterval.ni_timeIntervalWeekdayActive == 1))
{
cell.validityLabel.text = NSLocalizedString(#"Always", nil);
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID || timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
cell.validityLabel.text = NSLocalizedString(#"Not", nil);
}
else
{
timeInterval.ni_timeIntervalWeekdayActive = 1;
dateValidFrom = [NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */];
dateValidUntil = [NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */];
if (timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL)
{
cell.validityLabel.text = [NSString stringWithFormat:#"%# - 23:59:59 %#", [dateFormatter stringFromDate:dateValidFrom], NSLocalizedString(#"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:#"%# - %# %#", [dateFormatter stringFromDate:dateValidFrom], [dateFormatter stringFromDate:dateValidUntil], NSLocalizedString(#"oClock", nil)];
}
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
I have extracted the part of the code into a project and made it available for download.
I hope someone has an idea.
Thanks for your help

Finally I found a solution for the problem. After setting the locale in the code the picker didn't block.
Here ist the code I added after setTimeZone: in my code.
[cell.validityStartPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];
[cell.validityEndPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];

Related

How to modify selected UITexFiled value in Array of Textfield

Currently, I created Array of UITextField based on Response from Server in my UI, My response contains three types of response in single API, i.e I get 5 key and Values. Values contains Types like String, Date, Array, based on this when I select the UITextFiled the value must change according to that Particular TextFiled
Here my Sample Code:
for (int i=0;i<itemAttributeArray.count;i++){
UIColor *floatingLabelColor = [UIColor brownColor];
textField1 = [[JVFloatLabeledTextField alloc] initWithFrame:CGRectMake(16, y, width, height)];
textField1.delegate = self;
//Set tag 101
textField1.tag = 101;
NSLog(#"textField1.tag - %ld",(long)textField1.tag);
textField1.text = [[itemAttributeArray valueForKey:#"value"]objectAtIndex:i];
[self SetTextFieldBorder:textField1];
textField1.placeholder = [keyArr objectAtIndex:i];
textField1.font = [UIFont systemFontOfSize:kJVFieldFontSize];
// textField1.clearsOnBeginEditing = YES;
textField1.clearButtonMode = UITextFieldViewModeWhileEditing;
textField1.floatingLabelFont = [UIFont boldSystemFontOfSize:kJVFieldFloatingLabelFontSize];
textField1.floatingLabelTextColor = floatingLabelColor;
// textField1.translatesAutoresizingMaskIntoConstraints = NO;
[textField1 resignFirstResponder];
[_scroll addSubview:textField1];
[textFields addObject:textField1];
[textField1 release];
y += height + margin;
if ([[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i] isEqualToString:#"string"]){
NSLog(#"type - %#",[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i]);
}else if ([[[itemAttributeArray valueForKey:#"type"]
objectAtIndex:i] isEqualToString:#"date"]){
NSLog(#"type - %#",[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i]);
textField1.tag = 102;
[textField1 addTarget:self action:#selector(textFieldDidChange_dateChek)
forControlEvents:UIControlEventEditingDidBegin];
}else if ([[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i] isEqualToString:#"double"]){
NSLog(#"type - %#",[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i]);
}
-(void)textFieldDidChange_dateChek{
NSLog(#"iam called on first edit");
_picker_uiView.hidden = false;
[_datePickerView addTarget:self action:#selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];
}
- (void)datePickerValueChanged:(id)sender {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"h:mm a"];
textField1.text = [dateFormatter
stringFromDate:_datePickerView.date];
}
When I select the date value is entered in the last object to UITextfield but I selected index is 2nd but values changing on the last element of UITextfield
you are create the textfield in globally, thats the reason you get the last index only. in here assign the tag for each textfield as well as create the instance value.for e.g
for (int i=0;i<itemAttributeArray.count;i++){
UIColor *floatingLabelColor = [UIColor brownColor];
JVFloatLabeledTextField *textField1 = [[JVFloatLabeledTextField alloc] initWithFrame:CGRectMake(16, y, width, height)];
textField1.delegate = self;
//Set tag 101
textField1.tag = 101 + i;
NSLog(#"textField1.tag - %ld",(long)textField1.tag);
textField1.text = [[itemAttributeArray valueForKey:#"value"]objectAtIndex:i];
[self SetTextFieldBorder:textField1];
textField1.placeholder = [keyArr objectAtIndex:i];
textField1.font = [UIFont systemFontOfSize:kJVFieldFontSize];
// textField1.clearsOnBeginEditing = YES;
textField1.clearButtonMode = UITextFieldViewModeWhileEditing;
textField1.floatingLabelFont = [UIFont boldSystemFontOfSize:kJVFieldFloatingLabelFontSize];
textField1.floatingLabelTextColor = floatingLabelColor;
// textField1.translatesAutoresizingMaskIntoConstraints = NO;
[textField1 resignFirstResponder];
[_scroll addSubview:textField1];
[textFields addObject:textField1];
[textField1 release];
y += height + margin;
if ([[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i] isEqualToString:#"string"]){
NSLog(#"type - %#",[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i]);
}else if ([[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i] isEqualToString:#"date"]){
NSLog(#"type - %#",[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i]);
[textField1 addTarget:self action:#selector(textFieldDidChange_dateChek:)
forControlEvents:UIControlEventEditingDidBegin];
}else if ([[[itemAttributeArray valueForKey:#"type"] objectAtIndex:i] isEqualToString:#"double"]){
}
}
and handle the textfield action
-(void)textFieldDidChange_dateChek:(JVFloatLabeledTextField*)textfield{
NSLog(#"iam called on first edit");
_picker_uiView.hidden = false;
_datePickerView.tag = textfield.tag;
[textfield resignFirstResponder];
[_datePickerView addTarget:self action:#selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];
textfield.inputView = _datePickerView;
}
finally assign the value to the textfield as like follow
- (void)datePickerValueChanged:(UIDatePicker*)sender {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"h:mm a"];
// textField1.tag = 102;
for(id aSubView in [_scroll subviews]){
if([aSubView isKindOfClass:[JVFloatLabeledTextField class]])
{
JVFloatLabeledTextField *textFds=(JVFloatLabeledTextField*)aSubView;
if (textFds.tag == sender.tag) {
NSLog(#"dad == %#",[dateFormatter stringFromDate:sender.date]);
textFds.text = [dateFormatter stringFromDate:sender.date];
[textFds resignFirstResponder];
[sender removeFromSuperview];
break;
}
}
}
}

How to show image in specific time?

I have TableViewController and ViewController. In ViewController I save time and in TableViewController I want to show image in table cell if time more then 1:00. But my code doesn’t work… Help me please.
Code in TableViewController
_timeElapsed.text = [[NSUserDefaults standardUserDefaults] stringForKey:#"time0"];
if (self.timeElapsed.text >= #"1:00") {
UIImageView *imageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(28.5, 23, 25, 25)];
imageView2.backgroundColor = [UIColor clearColor];
[imageView2.layer setMasksToBounds:YES];
imageView2.tag = 3;
[cell.contentView addSubview:imageView2];
UIImageView *imgView2 = (UIImageView *)[cell.contentView viewWithTag:3];
imgView2.image = [UIImage imageNamed:#"accessory.png"];
}
#seto nugroho
Now my _timeElapsed.text = 2:57 but image doesn’t show
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: [NSString stringWithFormat:#"Cell%d", indexPath.row] forIndexPath:indexPath];
_timeElapsed.text = [[NSUserDefaults standardUserDefaults] stringForKey:#"time0"];
NSString *stringFromInput = self.timeElapsed.text;
NSString *stringToCompare = #"1:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"m:ss";
NSDate *timeFromInput = [dateFormatter dateFromString:stringFromInput];
NSDate *timeToCompare = [dateFormatter dateFromString:stringToCompare];
if ([timeFromInput compare:timeToCompare] == NSOrderedDescending) {
//actual time is greater
UIImageView *imageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(28.5, 23, 25, 25)];
imageView2.backgroundColor = [UIColor clearColor];
[imageView2.layer setMasksToBounds:YES];
imageView2.tag = 3;
[cell.contentView addSubview:imageView2];
UIImageView *imgView2 = (UIImageView *)[cell.contentView viewWithTag:3];
imgView2.image = [UIImage imageNamed:#"accessory.png"];
} else {
//not greater than 1 minutes
}
[tableView setSeparatorInset:UIEdgeInsetsMake(0, 70, 0, 1)];
return cell;
}
#iOS Geek
If timeString = #"0:05" and if (timeInSeconds > 1) image doesn’t show but in this case I see image.
NSString *timeString = #"0:05";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"mm:ss";
NSDate *timeDate = [formatter dateFromString:timeString];
formatter.dateFormat = #"mm";
int minutes = [[formatter stringFromDate:timeDate] intValue];
formatter.dateFormat = #"ss";
int seconds = [[formatter stringFromDate:timeDate] intValue];
int timeInSeconds = seconds + minutes * 60;
if (timeInSeconds > 1) {
UIImageView *imageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(28.5, 23, 25, 25)];
imageView2.backgroundColor = [UIColor clearColor];
[imageView2.layer setMasksToBounds:YES];
imageView2.tag = 3;
[cell.contentView addSubview:imageView2];
UIImageView *imgView2 = (UIImageView *)[cell.contentView viewWithTag:3];
imgView2.image = [UIImage imageNamed:#"accessory.png"];
}
You can not compare string values, unless you want to see if they are equal character by character(in which case you use "isEqualToString:").
Convert you time to integer values and then compare.
Update
You can use NSDateFormatter to get seconds and minutes from the time string:
NSString *timeString = #"3:31";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"mm:ss";
NSDate *timeDate = [formatter dateFromString:timeString];
formatter.dateFormat = #"mm";
int minutes = [[formatter stringFromDate:timeDate] intValue];
formatter.dateFormat = #"ss";
int seconds = [[formatter stringFromDate:timeDate] intValue];
int timeInSeconds = seconds + minutes * 60;
Your code doesn't work because you are comparing String, which obviously is not what you want.
You should convert your string to date and then compare it.
NSString *stringFromInput = self.timeElapsed.text;
NSString *stringToCompare = #"1:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"m:ss";
NSDate *timeFromInput = [dateFormatter dateFromString:stringFromInput];
NSDate *timeToCompare = [dateFormatter dateFromString:stringToCompare];
if ([timeFromInput compare:timeToCompare] == NSOrderedDescending) {
//actual time is greater
} else {
//not greater than 1 minutes
}
Turn warnings on. The compiler will warn you that you are comparing pointers with the >= operator, which is often undefined behaviour, and often nonsense, as in your case.
self.timeElapsed.text >= #"1:00"
compares two pointers. It compares a pointer to the location where the object self.timeElapsed.text is stored, and a pointer to the location where the object #"1:00" is stored. Which is obviously nonsense and completely unrelated to the actual values of the objects.
It's bad to compare time like this:
self.timeElapsed.text >= #"1:00"
Please convert it to NSDate or Int(not so good but easy). Like this:
[[self.timeElapsed.text componentsSeparatedByString:#":"] firstObject].intValue > 1

Date Picker - show time between two dates (UIDatePickerModeDateAndTime)

I'm currently showing a Date Picker of the kind UIDatePickerModeCountDownTimer that uses:
- (UIDatePicker *)datePicker {
if (!_datePicker) {
_datePicker = [[UIDatePicker alloc] init];
_datePicker.datePickerMode = UIDatePickerModeCountDownTimer;
_datePicker.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.8];
}
return _datePicker;
}
- (void)setDuration:(NSTimeInterval)duration {
_duration = duration;
self.datePicker.countDownDuration = _duration;
}
... date picker, and shows (in a label) the time from current date to date chosen in future with:
- (void)update {
if (self.time) {
[self setImage:nil forState:UIControlStateNormal];
NSString *title;
NSTimeInterval timeInterval = [self.time doubleValue];
if (self.ticking) {
NSMutableString *dateFormat = [[NSMutableString alloc] init];
if (timeInterval < 0) {
[dateFormat appendString:#"-"];
}
if (fabsf(timeInterval) > 60 * 60) {
[dateFormat appendString:#"hh:"];
}
[dateFormat appendString:#"mm:ss"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = dateFormat;
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
title = [formatter stringFromDate:date];
if ([self.time integerValue] > 0) {
self.circleView.backgroundColor = [UIColor colorWithRed:0.373 green:0.702 blue:0.522 alpha:1];
} else {
self.circleView.backgroundColor = [UIColor colorWithRed:0.820 green:0.373 blue:0.424 alpha:1];
}
} else {
NSMutableString *text = [[NSMutableString alloc] init];
if (fabsf(timeInterval) < 60) {
// Show seconds
[text appendFormat:#"%.0fs", timeInterval];
} else if (fabsf(timeInterval) < 60 * 60) {
// Show minutes
[text appendFormat:#"%.0fm", floorf(timeInterval / 60)];
} else {
// Show hours
[text appendFormat:#"%.0fh", floorf(timeInterval / 60 / 60)];
}
title = text;
self.circleView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.2];
}
[self setTitle:title forState:UIControlStateNormal];
return;
}
[self setTitle:nil forState:UIControlStateNormal];
[self setImage:[UIImage imageNamed:#"plus"] forState:UIControlStateNormal];
self.circleView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.05];
}
... but I switched the DatePicker to UIDatePickerModeDateAndTime and need to figure out how to update my update method with it.
I need to show month/day in addition to hour/minute/second in the label.
If you want a method like delegate, then this can help you..
Add target to your date picker....
[myDatePicker addTarget:self action:#selector(onPickerValueChanged:) forControlEvents:UIControlEventValueChanged];
Remove target in dealloc. Otherwise if your picker is scrolling and viewController is popped, app will crash.
- (void dealloc
{
[myPicker removeTarget:self action:#selector(onPickerValueChanged:) forControlEvents:UIControlEventValueChanged];
[myPicker release];//FOR NON ARC
[super dealloc];//FOR NON ARC
}
Implement value Change like
- (IBAction)onPickerValueChanged:(id)sender
{
[self update];
}

iPhone 4 iOS 7 Tableview lag when scrolling

I'm having some trouble with lag in my UITableview.
There aren't any problems on an iPhone 5 and after I started caching images in an NSDictionary, the iPhone 4 with iOS 6 became very responsive.
The problem remains on an iPhone 4 with iOS 7 however.
I've read trough some threads here with tips about making views opaque which I did but it didn't help. All my views except the labels are opaque (because if they are opaque they fill and that won't work for my purpose)
I do load a background image from the storyboard, do you guys know if this might be affecting performance? Is the storyboard inefficient when it comes to loading images?
Do you have any other tips for improving performance on a UITableView?
Thanks in advance!
Some code as requested,and these are the elements on the cell: http://imgur.com/Dcif6QE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
HomeListCell *cell;
if([self.eventList lastObject])
{
static NSString *CellIdentifier = #"HomeListCell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.userInteractionEnabled = YES;
cell.event = [self.eventList objectAtIndex:indexPath.row];
cell.parent = self;
if([cell.event.event.event_type count] != 0)
{
Event_Type *eventType = [cell.event.event.event_type firstObject];
NSString *imageName = #"HomeList_Type";
imageName = [imageName stringByAppendingString:eventType.name];
cell.eventTypeImage.image = [self.imageDict objectForKey:imageName];
}
//Laad de images hier uit de cache om scroll performance te verbeteren
int score = [cell.event.rating intValue];
[cell moveView:cell.ratingNumber duration:0.0 curve:UIViewAnimationCurveLinear x:0.0 y:0.0];
if(score > 0)
{
cell.ratingImage.image = [self.imageDict objectForKey:#"HomeList_plus"];
}
else if(score == 0)
{
cell.ratingImage.image = nil;
[cell moveView:cell.ratingNumber duration:0.0 curve:UIViewAnimationCurveLinear x:0.0 y:-10.0];
}
else
{
cell.ratingImage.image = [self.imageDict objectForKey:#"HomeList_min.png"];
score = -score;
}
cell.ratingNumber.text = [NSString stringWithFormat:#"%d", score];
[cell styleSelf];
}
And styleSelf has this code:
-(void) styleSelf {
LocationManager *locationManager = [LocationManager sharedInstance];
//Tekens die verandert moeten worden
NSCharacterSet *notAllowedY = [NSCharacterSet characterSetWithCharactersInString:#"ÿ"];
NSString *resultString = [[event.event.name componentsSeparatedByCharactersInSet:notAllowedY] componentsJoinedByString:#"y"];
//Afstand berekening
double eventLong = [self.event.location.address.gps_long doubleValue];
double eventLat = [self.event.location.address.gps_lat doubleValue];
CLLocation* locatie = [[CLLocation alloc]initWithLatitude:eventLat longitude:eventLong];
//Date + time
NSString *eventDate = event.opening;
eventDate = [eventDate stringByReplacingOccurrencesOfString:#"T" withString:#" "];
NSDate *theDate;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
if([eventDate hasSuffix:#"Z"])
{
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ssZ"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
theDate = [dateFormatter dateFromString:eventDate];
}
else
{
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
theDate = [dateFormatter dateFromString:eventDate];
}
[dateFormatter setDateFormat:#"HH:mm"];
self.timeNumberLabel.text = [dateFormatter stringFromDate:theDate];
self.timeNumberAfscheurLabel.text = [dateFormatter stringFromDate:theDate];
[dateFormatter setDateFormat:#"MM-dd"];
if ([[dateFormatter stringFromDate:theDate] isEqualToString:[dateFormatter stringFromDate:[NSDate date]]])
{
self.timeWhenLabel.text = NSLocalizedString(#"HomeList-Vandaag", nil);
self.timeWhenAfscheurLabel.text = NSLocalizedString(#"HomeList-Vandaag", nil);
}
else
{
[dateFormatter setDateFormat:#"MM"];
NSString *maand = [dateFormatter stringFromDate:theDate];
NSString *monthName = NSLocalizedString([#"Maand-" stringByAppendingString: maand], nil);
[dateFormatter setDateFormat:#"d"];
NSString *dag = [dateFormatter stringFromDate:theDate];
NSString *DatumString = [[dag stringByAppendingString:#" "]stringByAppendingString:monthName];
self.timeWhenLabel.text = [#" " stringByAppendingString:DatumString];
self.timeWhenAfscheurLabel.text = [#" " stringByAppendingString:DatumString];
}
//De cell vormen of de user gaat of niet
if([event.user_attends_event count] == 0)
{
[self moveView:self.nietAfgescheurdKnop duration:0 curve:UIViewAnimationCurveLinear x:0.0 y:0.0];
[self moveView:self.timeNumberAfscheurLabel duration:0 curve:UIViewAnimationCurveLinear x:0.0 y:0.0];
[self moveView:self.timeWhenAfscheurLabel duration:0 curve:UIViewAnimationCurveLinear x:0.0 y:0.0];
}
else
{
[self moveView:self.nietAfgescheurdKnop duration:0 curve:UIViewAnimationCurveLinear x:50.0 y:0.0];
[self moveView:self.timeNumberAfscheurLabel duration:0 curve:UIViewAnimationCurveLinear x:50.0 y:0.0];
[self moveView:self.timeWhenAfscheurLabel duration:0 curve:UIViewAnimationCurveLinear x:50.0 y:0.0];
}
self.event.userDistance = [locationManager getDistanceBetween:locatie];
if([self.event.userDistance isEqualToString:#"GPS error"])
{
self.distanceNumberLabel.text = NSLocalizedString(#"Extras-GPS", nil);
self.distanceTypeLabel.text = NSLocalizedString(#"Extras-UIT", nil);
self.distanceNumberLabel.textColor = [UIColor grayColor];
self.distanceTypeLabel.textColor = [UIColor grayColor];
}
else
{
NSString *placehold = self.event.userDistance;
placehold = [placehold stringByReplacingOccurrencesOfString:#"." withString:#","];
self.distanceNumberLabel.text = placehold;
self.distanceTypeLabel.text = NSLocalizedString(#"Extras-Km", nil);
self.distanceNumberLabel.textColor = [UIColor blackColor];
self.distanceTypeLabel.textColor = [UIColor blackColor];
}
// Configure the cell...
self.titleLabel.text = resultString;
self.tagsLabel.text = [event getMetadataString];
}
Your evil culprit is NSDateFormatter. This is a super-heavy object to create. You should create a single version of it somewhere and reuse it, setting the properties (formats, time zones, etc.) freely.
It's also a good idea to use Instruments -> Time Profiler to see exactly which methods are taking up time on the main thread.

iOS calendar integration to app

I having an app so i just added some event or remainder (football match,movie) in my app for some particular date and time.
And this add event i also want to display in iphone calendar.
thanks and regards.
Have you checked out EventKit?
You can use simple JTCalender for this
first oyu have to include JT Calender framework for the project
You have to create two views in your UIViewController:
The first view is JTCalendarMenuView and it represents the part with the months names. This view is optional.
The second view is JTHorizontalCalendarView or JTVerticalCalendarView, it represents the calendar itself.
Your UIViewController have to implement JTCalendarDelegate, all methods are optional.
in .h file
#import <UIKit/UIKit.h>
#import "CustomTableViewCell.h"
#import "JTCalendar/JTCalendar.h"
#interface CalendarViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,JTCalendarDelegate>
#property (strong, nonatomic) JTCalendarMenuView *calendarMenuView;
#property (strong, nonatomic) JTHorizontalCalendarView *calendarContentView;
#property (strong, nonatomic) JTCalendarManager *calendarManager;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *calendarContentViewHeight;
#end
.m file
------------
#import "CalendarViewController.h"
#import "ApptWindowView.h"
#import "SVProgressHUD.h"
#interface CalendarViewController () < UITextFieldDelegate>{
NSMutableDictionary *dayDateDict;
NSMutableArray*jsonDate,*dateAr1,*dateAr2;
UITableView *appointTableView;
CGSize screenRect;
NSString *dateAfterString;
int fontSize,headerBtnfont,height;
NSDateFormatter *dateFormat1 ;
NSString*cmpDay;
int count;
NSString * clickedDate;
NSString *day ;
NSMutableDictionary *_eventsByDate;
NSDate *_todayDate;
NSDate *_minDate;
NSDate *_maxDate;
NSDate *_dateSelected;
UIActivityIndicatorView *activityIndicator;
int i;
}
#end
#implementation CalendarViewController
- (void)viewDidLoad
{
[super viewDidLoad];
i=0;
dayDateDict=[[NSMutableDictionary alloc]init];
dateAr1=[[NSMutableArray alloc]init];
dateAr2=[[NSMutableArray alloc]init];
screenRect=[[UIScreen mainScreen]bounds].size;
//Create header here
self.view.backgroundColor=[UIColor colorWithRed:(CGFloat)233/255 green:(CGFloat)239/255 blue:(CGFloat)239/255 alpha:1];
UIView * headerView =[[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 55)];
headerView.backgroundColor =[UIColor whiteColor];
[self.view addSubview:headerView];
UILabel * titleLable =[[UILabel alloc]initWithFrame:CGRectMake(60, 25, [UIScreen mainScreen].bounds.size.width-120, 25)];
titleLable.text =#"CHOOSE APPOINTMENT";
titleLable.textAlignment = NSTextAlignmentCenter;
titleLable.font =[UIFont systemFontOfSize:12];
[headerView addSubview:titleLable];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:[UIImage imageNamed:#"back_btn.png"] forState:UIControlStateNormal];
[backButton setFrame:CGRectMake(15, 30, 45, 15)];
[backButton addTarget:self action:#selector(backAction) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:backButton];
UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
[nextButton setImage:[UIImage imageNamed:#"next_btn.png"] forState:UIControlStateNormal];
[nextButton setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width-60, 30, 45, 15)];
[nextButton addTarget:self action:#selector(continueAction) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:nextButton];
[self activityAction];
dispatch_async(dispatch_get_global_queue(0, 0),^{
dispatch_async(dispatch_get_main_queue(),^{
// [self createUI];
[self fetchSchedule];
_calendarManager = [JTCalendarManager new];
_calendarManager.delegate = self;
[self createMinAndMaxDate];
_calendarContentView=[JTHorizontalCalendarView new];
_calendarContentView.frame = CGRectMake(20, 100,[UIScreen mainScreen].bounds.size.width-40 , [UIScreen mainScreen].bounds.size.width-40);
_calendarContentView.backgroundColor=[UIColor whiteColor];
[_calendarManager setContentView:_calendarContentView];
[self.view addSubview:_calendarContentView];
_calendarMenuView=[JTCalendarMenuView new];
_calendarMenuView.frame=CGRectMake(20, 55,[UIScreen mainScreen].bounds.size.width-40 ,50);
_calendarMenuView.backgroundColor=[UIColor clearColor];
[self.view addSubview:_calendarMenuView];
[_calendarManager setMenuView:_calendarMenuView];
[_calendarManager setDate:[NSDate date]];
[activityIndicator stopAnimating];
});
});
[self createUI];
}
-(void)continueAction{
ApptWindowView *apptWindow=[[ApptWindowView alloc]init];
[self.navigationController pushViewController:apptWindow animated:YES];
}
- (UIView<JTCalendarDay> *)calendarBuildDayView:(JTCalendarManager *)calendar
{
JTCalendarDayView *view = [JTCalendarDayView new];
view.textLabel.font = [UIFont fontWithName:#"Avenir-Light" size:13];
view.textLabel.textColor = [UIColor blackColor];
return view;
}
NSError *error; NSURLResponse * urlResponse;
NSURL * url =[NSURL URLWithString:fetchScheduleService];
NSMutableURLRequest * request =[[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:50];
NSString * body =[NSString stringWithFormat:#"departmentId=%d",[SingletonClass sharedSingleton].deptId ];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSData * data =[NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
if (!data) {
[SVProgressHUD dismiss];
return;
}
id jsonResponse =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSLog(#"schedule jason---->%#",jsonResponse);
if ([[jsonResponse objectForKey:#"code"] isEqualToNumber:[NSNumber numberWithInt:200]]) {
jsonDate=[jsonResponse objectForKey:#"data"];
[self convertTimeStamp];
}
//dispatch_async(dispatch_get_main_queue(),^{
// [SVProgressHUD dismiss];
//[self createUI];
// });
// });
}
#pragma mark-Create UI/Table View
-(void)createUI{
appointTableView = [[UITableView alloc]init];
appointTableView.frame = CGRectMake(10, 100+screenRect.width-40+10, screenRect.width-20, screenRect.height-( 100+screenRect.width-40+10));
appointTableView.delegate = self;
appointTableView.dataSource = self;
appointTableView.backgroundColor =[UIColor clearColor];
appointTableView.showsVerticalScrollIndicator = NO;
appointTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:appointTableView];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[dayDateDict objectForKey:clickedDate] count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomTableViewCell * cell =(CustomTableViewCell*) [tableView cellForRowAtIndexPath:indexPath];
if (!cell) {
cell = [[CustomTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"calender"];
cell.backgroundColor = [UIColor clearColor];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[dateFormat1 setDateFormat:#"HH:mm"];
NSDate * aptTime =[dateFormat1 dateFromString:[[dayDateDict objectForKey:clickedDate]objectAtIndex:indexPath.row] ];
NSDate *dateAfter=[aptTime dateByAddingTimeInterval:(1800) ];
dateAfterString =[dateFormat1 stringFromDate:dateAfter];
NSString *dis=[NSString stringWithFormat:#"%#-%#",[[dayDateDict objectForKey:clickedDate]objectAtIndex:indexPath.row],dateAfterString];
cell.appointmentTime.text =dis;
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return 100;
}
return 60;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
ApptWindowView *apptWindow=[[ApptWindowView alloc]init];
[self.navigationController pushViewController:apptWindow animated:YES];
NSLog(#"clicked date-->%#",[[dayDateDict objectForKey:clickedDate]objectAtIndex:indexPath.row]);
NSDate * aptTime =[dateFormat1 dateFromString:[[dayDateDict objectForKey:clickedDate]objectAtIndex:indexPath.row] ];
NSDate *dateAfter=[aptTime dateByAddingTimeInterval:(1800) ];
dateAfterString =[dateFormat1 stringFromDate:dateAfter];
NSString *dis=[NSString stringWithFormat:#"%# to %# on %#",[[dayDateDict objectForKey:clickedDate]objectAtIndex:indexPath.row],dateAfterString,day];
[[NSUserDefaults standardUserDefaults]setObject:dis forKey:#"appointmentTime"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
#pragma mark-convert timeStamp to date
-(void)convertTimeStamp{
for( NSString*valueForDate in jsonDate){
NSTimeInterval timeSec=[valueForDate doubleValue];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeSec];
NSLog(#"\ndate are-->%#",date);
[self separateDate:date];
}
}
#pragma mark-separate date and Time
-(void)separateDate:(NSDate*)date1{
dateFormat1 = [[NSDateFormatter alloc] init];
[dateFormat1 setDateFormat:#"HH:mm"];
NSString * resultTime =[dateFormat1 stringFromDate:date1];
NSLog(#"date is-->%#",resultTime);
[dateFormat1 setDateFormat:#"dd-MM-YYYY"];
NSString *resultDay=[dateFormat1 stringFromDate:date1];
NSLog(#"day is-->%#",resultDay);
if([cmpDay isEqual:resultDay] || cmpDay==nil){
if(count!=1){
[dateAr1 addObject:resultTime];
}
if(count==1){
[dateAr2 addObject:resultTime];
}
}
else{
count=1;
dateAr2=[[NSMutableArray alloc]init];
[dateAr2 addObject:resultTime];
}
cmpDay=resultDay;
if(count!=1){
[dayDateDict setObject:dateAr1 forKey:resultDay];
}
else{
[dayDateDict setObject:dateAr2 forKey:resultDay];
}
NSLog(#"dictionary--->%#",dayDateDict);
}
#pragma mark - Buttons callback
- (IBAction)didGoTodayTouch
{
[_calendarManager setDate:_todayDate];
}
- (IBAction)didChangeModeTouch
{
_calendarManager.settings.weekModeEnabled = !_calendarManager.settings.weekModeEnabled;
[_calendarManager reload];
CGFloat newHeight = 300;
if(_calendarManager.settings.weekModeEnabled){
newHeight = 85.;
}
self.calendarContentViewHeight.constant = newHeight;
[self.view layoutIfNeeded];
}
#pragma mark - CalendarManager delegate
// Exemple of implementation of prepareDayView method
// Used to customize the appearance of dayView
- (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView
{
// Today
if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){
dayView.circleView.hidden = NO;
dayView.circleView.backgroundColor = [UIColor blueColor];
dayView.dotView.backgroundColor = [UIColor whiteColor];
dayView.textLabel.textColor = [UIColor whiteColor];
}
// Selected date
else if(_dateSelected && [_calendarManager.dateHelper date:_dateSelected isTheSameDayThan:dayView.date]){
dayView.circleView.hidden = NO;
dayView.circleView.backgroundColor = [UIColor redColor];
dayView.dotView.backgroundColor = [UIColor whiteColor];
dayView.textLabel.textColor = [UIColor whiteColor];
}
// Other month
else if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){
dayView.circleView.hidden = YES;
dayView.dotView.backgroundColor = [UIColor redColor];
dayView.textLabel.textColor = [UIColor lightGrayColor];
}
// Another day of the current month
else{
dayView.circleView.hidden = YES;
dayView.dotView.backgroundColor = [UIColor redColor];
dayView.textLabel.textColor = [UIColor blackColor];
}
if([self haveEventForDay:dayView.date]){
dayView.dotView.hidden = NO;
}
else{
dayView.dotView.hidden = YES;
}
}
- (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView
{
_dateSelected = dayView.date ;
NSLog(#"orginal Clicked day-->%#",dayView.date);
NSDateFormatter *dateFormat2 = [[NSDateFormatter alloc] init];
[dateFormat2 setDateFormat:#"dd-MM-YYYY"];
clickedDate =[dateFormat2 stringFromDate:_dateSelected];
NSLog(#"Selected date===>%#",clickedDate);
NSString* s= [dayDateDict objectForKey:clickedDate];
NSLog(#"time is===>%#",s);
[dateFormat2 setDateFormat:#"EEE, MMM dd "];
day =[dateFormat2 stringFromDate:_dateSelected];
NSLog(#"Selected day===>%#",day);
// Animation for the circleView
dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1);
[UIView transitionWithView:dayView
duration:.3
options:0
animations:^{
dayView.circleView.transform = CGAffineTransformIdentity;
[_calendarManager reload];
} completion:nil];
// Load the previous or next page if touch a day from another month
if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){
if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){
[_calendarContentView loadNextPageWithAnimation];
}
else{
[_calendarContentView loadPreviousPageWithAnimation];
}
}
[appointTableView reloadData];
}
#pragma mark - CalendarManager delegate - Page mangement
// Used to limit the date for the calendar, optional
- (BOOL)calendar:(JTCalendarManager *)calendar canDisplayPageWithDate:(NSDate *)date
{
return [_calendarManager.dateHelper date:date isEqualOrAfter:_minDate andEqualOrBefore:_maxDate];
}
- (void)calendarDidLoadNextPage:(JTCalendarManager *)calendar
{
// NSLog(#"Next page loaded");
}
- (void)calendarDidLoadPreviousPage:(JTCalendarManager *)calendar
{
// NSLog(#"Previous page loaded");
}
#pragma mark - Fake data
- (void)createMinAndMaxDate
{
_todayDate = [NSDate date];
// Min date will be 2 month before today
_minDate = [_calendarManager.dateHelper addToDate:_todayDate months:-3];
// Max date will be 2 month after today
_maxDate = [_calendarManager.dateHelper addToDate:_todayDate months:3];
}
- (BOOL)haveEventForDay:(NSDate *)date
{
if(i>=[dayDateDict allKeys].count){
i=0;
}
NSDateFormatter *dateFormatter;
dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd-MM-YYYY"];
NSString *key = [dateFormatter stringFromDate:date];
while(i<[dayDateDict allKeys].count){
if([key isEqual:[[dayDateDict allKeys]objectAtIndex:i]]){
i++;
return YES;
}
else
return NO;
}
return NO;
}
#pragma mark-Activity Indicator
-(void)activityAction{
CGSize windowSize =[UIScreen mainScreen].bounds.size;
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.frame = CGRectMake(windowSize.width/2-20, windowSize.height/2-55,40 ,40);
activityIndicator.color = [UIColor blackColor];
activityIndicator.alpha = 1;
[self.view addSubview:activityIndicator];
//[self placeSearchbaseId];
[activityIndicator startAnimating];
}
#end
I am fetching json data feching time form json as time stamp format and converting to local time
Then i am creating an events for it in the calender
You have third party apps like Kal which supports calendar integration. Check this link:
Kal Calendar
Hope it helps

Resources