Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: Method 25 times slower testing on device versus simulator

I have a method which runs incredibly slow testing in device (iPhone3G) comparing to simulator.

While the simulator can handle around 100 executions of the method in 1 second the device can only run 4 times thought the method in a second.

What can make it so sloooow?

CODE: Note: The method calculates a human friendly string from a two dates (start date and end date of an event).

-(void)calculateDiaDeInicioYFinTexto
{
    NSLog(@"inicio");
    NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];

    NSMutableString *auxString = [NSMutableString string];

    NSLocale *currLocale = [NSLocale currentLocale];

    NSString *stringFormatDay = [NSDateFormatter dateFormatFromTemplate:@"d" 
                                                                options:0 
                                                                 locale:currLocale];
    NSString *stringFormatDayMonth = [NSDateFormatter dateFormatFromTemplate:@"dMMMM" 
                                                                     options:0 
                                                                      locale:currLocale];
    NSString *stringFormatDayMonthYear = [NSDateFormatter dateFormatFromTemplate:@"dMMMMYYYY" 
                                                                         options:0 
                                                                          locale:currLocale];

    NSDateFormatter *formatterDay = [[NSDateFormatter alloc] init];
    [formatterDay setDateFormat:stringFormatDay];
    [formatterDay setLocale:currLocale];

    NSDateFormatter *formatterDayMonth = [[NSDateFormatter alloc] init];
    [formatterDayMonth setDateFormat:stringFormatDayMonth];
    [formatterDayMonth setLocale:currLocale];

    NSDateFormatter *formatterDayMonthYear = [[NSDateFormatter alloc] init];
    [formatterDayMonthYear setDateFormat:stringFormatDayMonthYear];
    [formatterDayMonthYear setLocale:currLocale];


    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *dateComponentsNow = [calendar components:(NSYearCalendarUnit |
                                                                NSMonthCalendarUnit | 
                                                                NSDayCalendarUnit)
                                                      fromDate:[NSDate date]];
    NSDateComponents *dateComponentsInicio = [calendar components:(NSYearCalendarUnit |
                                                                   NSMonthCalendarUnit | 
                                                                   NSDayCalendarUnit)
                                                         fromDate:self.diaDeInicio];
    NSDate *diaDeInicioTimeless = [calendar dateFromComponents:dateComponentsInicio];

    NSDateComponents *dateComponentsFin = [calendar components:(NSYearCalendarUnit | 
                                                                NSMonthCalendarUnit |
                                                                NSDayCalendarUnit) 
                                                      fromDate:self.diaDeFin];
    NSDate *diaDeFinTimeless = [calendar dateFromComponents:dateComponentsFin];


    if ( [diaDeInicioTimeless isEqualToDate:diaDeFinTimeless] ) {
        // dates are the same
        if ( dateComponentsInicio.year == dateComponentsNow.year ) {
            // date is in the current year
            [auxString appendFormat:@"%@", [formatterDayMonth stringFromDate:self.diaDeInicio]];
        } else {
            // date is in another year
            [auxString appendFormat:@"%@", [formatterDayMonthYear stringFromDate:self.diaDeInicio]];
        }
    } else {
        // dates are different
        if ( dateComponentsInicio.year == dateComponentsFin.year ) {
            // years are the same
            if ( dateComponentsInicio.month == dateComponentsFin.month ) {
                // Months are the same
                if ( dateComponentsInicio.year == dateComponentsNow.year ) {
                    // date is in the current year
                    [auxString appendFormat:@"%@ - %@", 
                     [formatterDay stringFromDate:self.diaDeInicio],
                     [formatterDayMonth stringFromDate:self.diaDeFin]];                    
                } else {
                    // date is in another year
                    [auxString appendFormat:@"%@ - %@", 
                     [formatterDay stringFromDate:self.diaDeInicio],
                     [formatterDayMonthYear stringFromDate:self.diaDeFin]];                                        
                }
            } else {
                // Months are different
                if ( dateComponentsInicio.year == dateComponentsNow.year ) {
                    // date is in the current year
                    [auxString appendFormat:@"%@ - %@", 
                     [formatterDayMonth stringFromDate:self.diaDeInicio],
                     [formatterDayMonth stringFromDate:self.diaDeFin]];                    
                } else {
                    // date is in another year
                    [auxString appendFormat:@"%@ - %@", 
                     [formatterDayMonth stringFromDate:self.diaDeInicio],
                     [formatterDayMonthYear stringFromDate:self.diaDeFin]];                    
                }
            }
        } else {
            // Years are different
            [auxString appendFormat:@"%@ - %@", 
             [formatterDayMonthYear stringFromDate:self.diaDeInicio],
             [formatterDayMonthYear stringFromDate:self.diaDeFin]];            
        }
    }
    self.diaDeInicioYFinTexto = auxString;
    [formatterDay release];
    [formatterDayMonth release];
    [formatterDayMonthYear release];
    [localPool release]; 

    NSLog(@"Fin");
}
like image 832
David Casillas Avatar asked Feb 29 '12 14:02

David Casillas


4 Answers

iOS Devices are considerably less powerful than the computer that you are running the simulator on. The iOS simulator does not emulate the ARM proccessor and so it runs it at full speed.

In addition, the reason that this particular method is so slow is because of the creation of the NSDateFormatter and NSCalendar objects. Those are fairly expensive to create and should be cached in an instance variable/property if you want to use them multiple times.

like image 71
DHamrick Avatar answered Oct 24 '22 05:10

DHamrick


You should cache this variable, it's very slow. Call this method once.

NSCalendar *calendar = [NSCalendar currentCalendar];
like image 39
NeverBe Avatar answered Oct 24 '22 07:10

NeverBe


Avoid using NSDateFormatter in loop.

I fixed it by converting date to string using stringWithFormat and then breaking the components by using componentsSeparatedByString.

NSString *stringDate = [NSString stringWithFormat:@"%@",mydate];
NSArray *stringArray = [stringDate componentsSeparatedByString: @" "];
NSArray *timeArray = [stringArray[1] componentsSeparatedByString: @":"];

By doing this, I was able to execute my loop in less than a sec from couple of seconds.

Hope this will help.

like image 1
Sumoanand Avatar answered Oct 24 '22 07:10

Sumoanand


Instantiating NSDateFormatter and NSCalendar are not non-trivial operations. Creating an NSDateFormatter can take up to 250ms on an iPhone 4s, on my testing. Avoid re-creating of these objects, keeping them either as class ivars or static objects if possible. Re-use whenever you can.

like image 1
vsanthanam510 Avatar answered Oct 24 '22 07:10

vsanthanam510