如何同时用数据和 运行 一个 activity 指示器填充 pickerview?
How to fill a pickerview with data and run an activity indicator at the same time?
我有一个方法可以从 Web 服务加载数据并填充数组,它工作正常(我们称之为 "get_data")。我使用此数组 ("arr") 作为选择器视图 ("pv") 的数据源,它也工作正常,当我 运行 我的应用程序时,选择器视图充满了项目。有一天我决定使用一个 "activity indicator" ("ai"),现在 "pv" 总是空的,我不知道如何修复它。接下来是我的代码:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; }
//-------------------------------------------------------------------
- (void) get_data { // CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; } // SPINNING STOPS AFTER LONG TASK.
//-------------------------------------------------------------------
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1; }
//-------------------------------------------------------------------
- (NSInteger)pickerView :(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component {
return [arr count]; }
//-------------------------------------------------------------------
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component {
return [arr objectAtIndex:row]; }
//-------------------------------------------------------------------
- (void) pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger )row
inComponent:(NSInteger )component {
index = [pv selectedRowInComponent:0]; } // INDEX IS A GLOBAL INT.
//-------------------------------------------------------------------
- ( NSAttributedString * ) pickerView:(UIPickerView *)pickerView
attributedTitleForRow:(NSInteger)row
forComponent:(NSInteger)component {
NSString * title = [arr objectAtIndex:row];
NSAttributedString * attString = [[NSAttributedString alloc]
initWithString:title attributes:
@{NSForegroundColorAttributeName:
[UIColor blackColor]}];
return attString; }
我之前用 "activity indicators" 和 "performSelector" 使用过,它们运行良好。我不明白的是为什么 pickerview 方法不再适用于数组,所以,我的问题是:如何同时用数据和 运行 一个 activity 指示器填充一个 pickerview ?
如果我像这样更改我的 viewDidLoad,pickerview 会工作,但 activity 指示器不会:
- (void) viewDidLoad {
[super viewDidLoad];
/* [ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; */
[self get_data];
}
当您使用 performSelector:
时,它会在同一个线程上执行,就像您直接调用选择器一样。
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0];
}
- (void) get_data {
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
}
这等同于:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self get_data]; // FILL ARRAY.
}
或简单地:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
}
如果您的 Web 服务在不同的线程或块中执行并允许您附加完成响应程序,您应该将 [ai stopAnimation];
放在那里。
如果不是这种情况,并且您正在主线程上同步调用 Web 服务以获取数据(永远不要在主线程上执行阻塞网络操作) ,您可以改为将其全部转移到后台线程:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0L), ^{
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
dispatch_async(dispatch_get_main_queue(), ^{
[ai stopAnimations]; // SPINNING STOPS AFTER LONG TASK.
});
});
确保已设置选择器视图的 dataSource
和 delegate
。 Web 服务完成后,您需要使用更新后的 arr
.
重新加载选择器的数据源
- (void) viewDidLoad {
[super viewDidLoad];
pv.dataSource = self;
pv.delegate = self;
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; }
- (void) get_data {
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
[pv reloadAllComponents];
}
我有一个方法可以从 Web 服务加载数据并填充数组,它工作正常(我们称之为 "get_data")。我使用此数组 ("arr") 作为选择器视图 ("pv") 的数据源,它也工作正常,当我 运行 我的应用程序时,选择器视图充满了项目。有一天我决定使用一个 "activity indicator" ("ai"),现在 "pv" 总是空的,我不知道如何修复它。接下来是我的代码:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; }
//-------------------------------------------------------------------
- (void) get_data { // CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; } // SPINNING STOPS AFTER LONG TASK.
//-------------------------------------------------------------------
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1; }
//-------------------------------------------------------------------
- (NSInteger)pickerView :(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component {
return [arr count]; }
//-------------------------------------------------------------------
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component {
return [arr objectAtIndex:row]; }
//-------------------------------------------------------------------
- (void) pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger )row
inComponent:(NSInteger )component {
index = [pv selectedRowInComponent:0]; } // INDEX IS A GLOBAL INT.
//-------------------------------------------------------------------
- ( NSAttributedString * ) pickerView:(UIPickerView *)pickerView
attributedTitleForRow:(NSInteger)row
forComponent:(NSInteger)component {
NSString * title = [arr objectAtIndex:row];
NSAttributedString * attString = [[NSAttributedString alloc]
initWithString:title attributes:
@{NSForegroundColorAttributeName:
[UIColor blackColor]}];
return attString; }
我之前用 "activity indicators" 和 "performSelector" 使用过,它们运行良好。我不明白的是为什么 pickerview 方法不再适用于数组,所以,我的问题是:如何同时用数据和 运行 一个 activity 指示器填充一个 pickerview ?
如果我像这样更改我的 viewDidLoad,pickerview 会工作,但 activity 指示器不会:
- (void) viewDidLoad {
[super viewDidLoad];
/* [ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; */
[self get_data];
}
当您使用 performSelector:
时,它会在同一个线程上执行,就像您直接调用选择器一样。
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0];
}
- (void) get_data {
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
}
这等同于:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self get_data]; // FILL ARRAY.
}
或简单地:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
}
如果您的 Web 服务在不同的线程或块中执行并允许您附加完成响应程序,您应该将 [ai stopAnimation];
放在那里。
如果不是这种情况,并且您正在主线程上同步调用 Web 服务以获取数据(永远不要在主线程上执行阻塞网络操作) ,您可以改为将其全部转移到后台线程:
- (void) viewDidLoad {
[super viewDidLoad];
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0L), ^{
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
dispatch_async(dispatch_get_main_queue(), ^{
[ai stopAnimations]; // SPINNING STOPS AFTER LONG TASK.
});
});
确保已设置选择器视图的 dataSource
和 delegate
。 Web 服务完成后,您需要使用更新后的 arr
.
- (void) viewDidLoad {
[super viewDidLoad];
pv.dataSource = self;
pv.delegate = self;
[ai startAnimation]; // ACTIVITY INDICATOR STARTS SPINNING.
[self performSelector:@selector( get_data ) // FILL ARRAY.
withObject:nil
afterDelay:0]; }
- (void) get_data {
// CALL WEB SERVICE, FILL ARRAY WITH JSON DATA.
[ai stopAnimation]; // SPINNING STOPS AFTER LONG TASK.
[pv reloadAllComponents];
}