andrey
andrey

Reputation: 681

How to optimize code and load UIPickerView with data fast?

I'm creating UIPickerView with 2 components, for minutes and seconds. I've created picker in UI and want to fill it with data and below is code how I fill it with numbers from 0 - 59. I want to make it look like circular thats why kSizeOfPicker is 60000. When user press the button window with picker appears but it slows app very much, because this code is in viewDidLoad. How can I fix it?

NSString *stringValue = [[NSString alloc] init];

for(int i=0; i<kSizeOfPicker; i++)
{
    stringValue = [NSString stringWithFormat:@"%d", i%60];


    [_minutesArray addObject:stringValue];
    [_secondsArray addObject:stringValue];
}

and here are data source and delegate methods:

#pragma mark - UIPickerView DataSource Methods


- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}


- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent :    (NSInteger)component
{

if (component==0)
{
    return [_minutesArray count];
}
else
{
    return [_secondsArray count];
}

}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *title;
switch (component)
{

    case 0:
        title = [NSString stringWithFormat:@"%@ minutes", [_minutesArray objectAtIndex:row]];

        return title;
        break;
    case 1:
        title = [NSString stringWithFormat:@"%@ seconds", [_secondsArray objectAtIndex:row]];
        return title;
        break;
}
return nil;
}

#pragma mark - UIPickerView Delegate Methods

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{

if (component == 0)
    _firstComponent = [_minutesArray objectAtIndex:row];

else
    _secondComponent = [_secondsArray objectAtIndex:row];

}

Upvotes: 2

Views: 396

Answers (3)

Sandip
Sandip

Reputation: 176

If the problem is loading time due to heavy data than either you can put these code in view did appear or you can put the code in Dispatch queue , It will not block your main thread and let your screen loads quickly.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    // here you can do your heavy operation 
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Update your UI
    });
});

Or if you want to display time only than you can use UIDatePicker and set its mode :

Date Picker Mode The mode of the date picker.

typedef enum {
   UIDatePickerModeTime,
   UIDatePickerModeDate,
   UIDatePickerModeDateAndTime,
   UIDatePickerModeCountDownTimer
} UIDatePickerMode;

Hope it helps you.

Thank you.

Upvotes: 0

rintaro
rintaro

Reputation: 51911

You don't need prepare all data in NSArray to archive circular pickerview. Following code virtually prepares +-50 duplicate datasets around selected row. In pickerView:didSelectRow:inComponent: delegate method, you can reset selected row.

@interface MyViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@property (assign, nonatomic) NSUInteger minutes;
@property (assign, nonatomic) NSUInteger seconds;
@end

@implementation MyViewController

#define VALUE_THRESHOLD 60
#define PICKER_DUPLICATES 100
#define CENTER_ROW (VALUE_THRESHOLD * PICKER_DUPLICATES / 2)

- (void)viewDidLoad {
    [super viewDidLoad];
    [_pickerView selectRow:_minutes + CENTER_ROW inComponent:0 animated:NO];
    [_pickerView selectRow:_seconds + CENTER_ROW inComponent:1 animated:NO];
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return VALUE_THRESHOLD * PICKER_DUPLICATES;
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    return [NSString stringWithFormat:@"%d", row % VALUE_THRESHOLD];
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    NSInteger actualRow = row % VALUE_THRESHOLD;

    // reset to center dataset
    [pickerView selectRow: actualRow + CENTER_ROW inComponent:component animated:NO];

    // do anything what you want;
    if(component == 0) {
        _minutes = actualRow;
    }
    else {
        _seconds = actualRow;
    }
}

@end

Upvotes: 1

NeverHopeless
NeverHopeless

Reputation: 11233

Use UIDatePicker instead of 60000 iterations it will make your life easier. Set its mode to Time.

Upvotes: 0

Related Questions