Reputation: 157
I have a IPhone app that has 10 NSTimer
functions that check every .5 second on a view that scrolls. Each timer has 3 labels, 1 text field and 1 UIImageView
. All 30 labels, 10 text fields and 10 UIImageViews
need to scroll.
Problem 1 is the view does not scroll smooth. I have seen some suggestions on here and have tried then with no success. When you start to scroll, it takes a split second to start, then it jumps about 150 pixels then it starts scrolling.
Problem 2 is that when it is scrolling, the text fields and labels are not being updated by the NSTimer.. When you stop scrolling the fields jump to the correct time. is this just to much for the iPhone to handle or is there something I am missing?
I added some of my "rude" code. This is just one NSTimer that is checking every 0.5 seconds. I also have all my pointers releasing and set to nil in the viewDidUnload. The dates are different where they will have holiday info and possible more info added in the array at a later date.
Update:I have ran this app on my iPhone 4 and it is NOT smooth. It IS smooth however in the iPhone simulator.
-(void)updateUSDTimer {
NSMutableArray *usdMarketHours = [[NSMutableArray alloc] init];
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"2", @"29", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:0];// open WED
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"2", @"29", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:1];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"1", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:2];// open THU
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"1", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:3];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"2", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:4];// open FRI
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"2", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:5];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"5", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:6];// open MON
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"5", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:7];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"6", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:8];// open TUE
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"6", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:9];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"7", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:10];// open WED
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"7", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:11];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"8", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:12];// open THU
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"8", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:13];// close
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"9", @"8", @"00", @"00", @"EST", @"Holiday list", nil ] atIndex:14];// open FRI
[usdMarketHours insertObject:[NSArray arrayWithObjects:@"2012", @"3", @"9", @"17", @"00", @"00", @"EST", @"", nil ] atIndex:15];// close
int USDarrayLength = [usdMarketHours count];
int index0USD = 0;
int index1USD = 1;
int index2USD = 2;
int u = 0;
// ---------------------------------------------- START FOR LOOP ---------------------------------------------------------->
for (u=0; u<USDarrayLength; u++) {
NSDate *USDnow = [NSDate date];
// ------------------------------------------------------->
// Convert to timeA
NSString *USDyear = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:0];
NSString *USDmonth = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:1];
NSString *USDday = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:2];
NSString *USDhour = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:3];
NSString *USDminute = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:4];
NSString *USDsecond = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:5];
NSString *USDtimeZone = [[usdMarketHours objectAtIndex:index0USD] objectAtIndex:6];
NSDateComponents *USDcompA = [[NSDateComponents alloc] init];
[USDcompA setYear:[USDyear intValue]];
[USDcompA setMonth:[USDmonth intValue]];
[USDcompA setDay:[USDday intValue]];
[USDcompA setHour:[USDhour intValue]];
[USDcompA setMinute:[USDminute intValue]];
[USDcompA setSecond:[USDsecond intValue]];
[USDcompA setTimeZone:[NSTimeZone timeZoneWithAbbreviation:[NSString stringWithFormat:@"%@", USDtimeZone]]];
USDcal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
USDtimeADate = [USDcal dateFromComponents:USDcompA];
// Using NSDateFormatter pointers, set format for array[]/GMT/Local times.
// timeAFormatter for array date
[USDtimeAFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeAFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:USDtimeZone]]; // Array Time Zone
[USDtimeAFormatterGMT setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeAFormatterGMT setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]]; // String "GMT"
[USDtimeAFormatterLocal setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeAFormatterLocal setTimeZone:[NSTimeZone localTimeZone]]; // Local time
// ------------------------------------------------------->
// Convert to timeB
NSString *USDyearb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:0];
NSString *USDmonthb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:1];
NSString *USDdayb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:2];
NSString *USDhourb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:3];
NSString *USDminuteb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:4];
NSString *USDsecondb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:5];
NSString *USDtimeZoneb = [[usdMarketHours objectAtIndex:index1USD] objectAtIndex:6];
NSDateComponents *USDcompB = [[NSDateComponents alloc] init];
[USDcompB setYear:[USDyearb intValue]];
[USDcompB setMonth:[USDmonthb intValue]];
[USDcompB setDay:[USDdayb intValue]];
[USDcompB setHour:[USDhourb intValue]];
[USDcompB setMinute:[USDminuteb intValue]];
[USDcompB setSecond:[USDsecondb intValue]];
[USDcompB setTimeZone:[NSTimeZone timeZoneWithAbbreviation:[NSString stringWithFormat:@"%@", USDtimeZoneb]]];
USDcalb = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
USDtimeBDate = [USDcalb dateFromComponents:USDcompB];
[USDtimeBFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeBFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:USDtimeZoneb]]; // Array Time Zone
[USDtimeBFormatterGMT setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeBFormatterGMT setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]]; // String "GMT"
[USDtimeBFormatterLocal setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeBFormatterLocal setTimeZone:[NSTimeZone localTimeZone]]; // String "GMT"
// ----------------------------------------------------------------------------------->
// Convert to timeC
NSString *USDyearc = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:0];
NSString *USDmonthc = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:1];
NSString *USDdayc = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:2];
NSString *USDhourc = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:3];
NSString *USDminutec = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:4];
NSString *USDsecondc = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:5];
NSString *USDtimeZonec = [[usdMarketHours objectAtIndex:index2USD] objectAtIndex:6];
NSDateComponents *USDcompC = [[NSDateComponents alloc] init];
[USDcompC setYear:[USDyearc intValue]];
[USDcompC setMonth:[USDmonthc intValue]];
[USDcompC setDay:[USDdayc intValue]];
[USDcompC setHour:[USDhourc intValue]];
[USDcompC setMinute:[USDminutec intValue]];
[USDcompC setSecond:[USDsecondc intValue]];
[USDcompC setTimeZone:[NSTimeZone timeZoneWithAbbreviation:[NSString stringWithFormat:@"%@", USDtimeZonec]]];
USDcalc = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
USDtimeCDate = [USDcalb dateFromComponents:USDcompC];
[USDtimeCFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeCFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:USDtimeZonec]]; // Array Time Zone
[USDtimeCFormatterGMT setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeCFormatterGMT setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]]; // String "GMT"
[USDtimeCFormatterLocal setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
[USDtimeCFormatterLocal setTimeZone:[NSTimeZone localTimeZone]]; // String "GMT"
// ------------------------------------------------------------------------------------>
// create doubles, from timeIntervalSince1970. ex: 12345678945613.13489
double timeAInterval = [USDtimeADate timeIntervalSince1970];
double timeNowInterval = [USDnow timeIntervalSince1970];
double timeBInterval = [USDtimeBDate timeIntervalSince1970];
//double timeCInterval = [timeCDate timeIntervalSince1970];
// mathA = this is how long the market is open/closed. the before time.
// timeAInterval = array date before present time
// timeNowInterval = date of present time
// timeBInterval = array date of after present time
// timeCInterval = array date of 2nd after present time
// ------------------------------------------------------------------------------------>
// if statement to find the correct array dates
if((timeAInterval < timeNowInterval) && (timeBInterval > timeNowInterval))
{
// ------------------------------------------------------------------------------------>
// Even index(i) are OPEN times, Odd index are CLOSED times.
NSString *USDindex0Prefix = @"";
NSString *USDindex1Prefix = @"";
if(index0USD % 2 ==0)
{
// Market is presently -------------------> OPEN
// NSLog(@"%i is even number", index0);
//NSLog(@"MARKET IS OPEN");
USDindex0Prefix = @"Closes : ";
USDindex1Prefix = @"Opens : ";
USDremainPrefix = @"Closes in: ";
UIImage *image = [UIImage imageNamed:@"USD_flag.png"];
[USDlightOpenOrClose setImage:image];
}else{
// Market is presently -------------------> CLOSED
//NSLog(@"%i is odd number", index0);
//NSLog(@"MARKET IS CLOSED");
USDindex1Prefix = @"Closes : ";
USDindex0Prefix = @"Opens : ";
USDremainPrefix = @"Opens in: ";
UIImage *image = [UIImage imageNamed:@"USD_flag_BW.png"];
[USDlightOpenOrClose setImage:image];
}
// ------------------------------------------------------------------------------------>
// Math to seperate hour, minutes, seconds
NSTimeInterval elapsedTime = [USDtimeBDate timeIntervalSinceNow];
div_t h = div(elapsedTime, 3600);
int hours = h.quot;
div_t m = div(h.rem, 60);
int minutes = m.quot;
int seconds = m.rem;
// Remove negative sign if neg number. If not, do nothing: hours, minutes, seconds are int
if(hours<0){
hours = hours * -1;
}
if(minutes<0){
minutes = minutes * -1;
}
if(seconds<0){
seconds = seconds * -1;
}
// Formats the UITextField remaining time.
if(hours <= 0){// hours less than or equal to 0
USDRemainTime.text = [NSString stringWithFormat:@"%@ %.2dm %.2ds", USDremainPrefix,minutes, seconds];
USDRemainTime.textColor = [UIColor blackColor];
USDRemainTime.font = [UIFont systemFontOfSize:14];
}
if(hours > 0){// hours more than 0
USDRemainTime.text = [NSString stringWithFormat:@"%@ %dh %.2dm ", USDremainPrefix,hours, minutes];
USDRemainTime.textColor = [UIColor blackColor];
USDRemainTime.font = [UIFont systemFontOfSize:14];
}
if((hours >= 1) && (hours < 10)){// hours between 1hr and 10hr
USDRemainTime.text = [NSString stringWithFormat:@"%@ %.1dh %.2dm", USDremainPrefix ,hours, minutes];
USDRemainTime.textColor = [UIColor blackColor];
USDRemainTime.font = [UIFont systemFontOfSize:14];
}
if((hours <= 0) && (minutes < 5)){// less than 5 min
// Less than 5 min, turn text red.
USDRemainTime.text = [NSString stringWithFormat:@"%@ %.2dm %.2ds", USDremainPrefix, minutes, seconds];
USDRemainTime.textColor = [UIColor redColor];
USDRemainTime.font = [UIFont boldSystemFontOfSize:16];
}
// ------------------------------------------------------------------------------------>
// Format timeA and timeB with NSDateFormatter. Use in text fields and labels
NSDateFormatter *USDtimeAFormatted = [[NSDateFormatter alloc] init];
[USDtimeAFormatted setDateFormat:@"EEE. MMM. dd, yyyy HH:mm:ss z"];
NSDateFormatter *USDtimeNoSeconds = [[NSDateFormatter alloc] init];
[USDtimeNoSeconds setDateFormat:@"EEE. MMM. dd, yyyy HH:mm z"];
// This sets the Open/Close labels to Country time(array time), GMT time, or local time
// 0 = Country timezone (array timezone)
// 1 = GMT timezone
// 2 = local timezone
int desiredFormat = 0;
if(desiredFormat == 0){
[USDtimeAFormatted setTimeZone:[NSTimeZone timeZoneWithAbbreviation:USDtimeZoneb]];
NSString *USDfinalRemainb = [USDtimeAFormatted stringFromDate:USDtimeBDate];
USDStartTime.text = [NSString stringWithFormat:@"%@ %@", USDindex0Prefix, USDfinalRemainb];
[USDtimeAFormatted setTimeZone:[NSTimeZone timeZoneWithAbbreviation:USDtimeZonec]];
NSString *USDfinalRemainc = [USDtimeAFormatted stringFromDate:USDtimeCDate];
USDCloseTime.text = [NSString stringWithFormat:@"%@ %@", USDindex1Prefix, USDfinalRemainc];
//[USDtimeNoSeconds setTimeZone:[NSTimeZone localTimeZone]];
[USDtimeNoSeconds setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"EST"]];
NSString *USDNowTime = [USDtimeNoSeconds stringFromDate:USDnow];
USDPresentTime.text = [NSString stringWithFormat:@"Present Time: %@", USDNowTime];
}
if(desiredFormat == 1){
[USDtimeAFormatted setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
NSString *USDfinalRemainb = [USDtimeAFormatted stringFromDate:USDtimeBDate];
USDStartTime.text = [NSString stringWithFormat:@"%@ %@", USDindex0Prefix, USDfinalRemainb];
[USDtimeAFormatted setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
NSString *USDfinalRemainc = [USDtimeAFormatted stringFromDate:USDtimeCDate];
USDCloseTime.text = [NSString stringWithFormat:@"%@ %@", USDindex1Prefix, USDfinalRemainc];
[USDtimeAFormatted setTimeZone:[NSTimeZone localTimeZone]];
NSString *USDNowTime = [USDtimeAFormatted stringFromDate:USDnow];
USDPresentTime.text = [NSString stringWithFormat:@"Present Time: %@", USDNowTime];
}
if(desiredFormat == 2){
[USDtimeAFormatted setTimeZone:[NSTimeZone localTimeZone]];
NSString *USDfinalRemainb = [USDtimeAFormatted stringFromDate:USDtimeBDate];
USDStartTime.text = [NSString stringWithFormat:@"%@ %@", USDindex0Prefix, USDfinalRemainb];
[USDtimeAFormatted setTimeZone:[NSTimeZone localTimeZone]];
NSString *USDfinalRemainc = [USDtimeAFormatted stringFromDate:USDtimeCDate];
USDCloseTime.text = [NSString stringWithFormat:@"%@ %@", USDindex1Prefix, USDfinalRemainc];
[USDtimeAFormatted setTimeZone:[NSTimeZone localTimeZone]];
NSString *USDNowTime = [USDtimeAFormatted stringFromDate:USDnow];
USDPresentTime.text = [NSString stringWithFormat:@"Present Time: %@", USDNowTime];
}
// ------------------------------------------------------------------------------------>
// disables the textField from a user interaction
USDRemainTime.enabled = NO;
[USDRemainTime setUserInteractionEnabled:NO];
}else{
index0USD++;
index1USD++;
index2USD++;
// if incremented that means that we must check the next array to see if the present date is between two arrays
}
}
}
- (void)viewDidLoad
{
forexTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateForexTimer) userInfo:nil repeats:YES];
USDTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateUSDTimer) userInfo:nil repeats:YES];
[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.bounds.size;
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
Upvotes: 3
Views: 1294
Reputation: 706
I believe that the first problem is caused by doing too many operations (checks) on the main thread. Since all UI operations (in your case, scrolling) are also handled on the main thread, they will only get called when the other checks have been finished. This might be the cause of the initial stutter you notice. The second problem is probably due to the way NSTimers work - they're not real-time. Even if a timer's firing time has passed, it will only be called if the thread that is responsible for the timer is idle. So only once the view has stopped scrolling will the timer be checked.
You could try adding the checks in a different thread and only call the main thread to update the UI elements if necessary.
Upvotes: 0
Reputation: 6176
well, probably it may be better to use just 1 timer and manage all scrolling inside it, but a better way (depending on what are you trying do do) could be just to use UIView animation block with animateWithDuration:animations: and let all the hard work to it. what kind of animations are you doing with your UIViews?
Upvotes: 1