我正在使用一个 ViewController,它代表和数据源 2 个不同的 TableView 。根据用户希望看到的内容( View 中某些区域的“touchesBegan”发生切换。
viewcontroller 是选项卡式应用程序的 3 个子 Controller 之一。
tableviews 之间的交替工作很好。我获得了正确的数据、布局等,并且可以根据需要随时在它们之间进行更改。
第一个 tableview 不包含困难的数据,因此它会在几毫秒内加载。
第二个 tableview2 包含大约需要 2-3 秒才能加载的数据(取决于 coredata 中的实体数量)。当此数据加载和 tableview2 重绘时,我显示了 MBProgressHUD。这也有效。
问题:如果我在加载 table2 时与 tabbarcontroller 交互并且 hud 正在旋转,应用程序会“卡住”hud 无限长地运行并且任何用户交互都被禁用.以及点击的标签不会打开。
代码:touchesBegan 函数
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (isLoadingAllMonth) {
return;
}
[[MBProgressHUD HUDForView:self.view]removeFromSuperview];
UITouch *touch = [[event allTouches]anyObject];
int viewTag = touch.view.tag; // 1 for thisMonth, 2 for allMonth
if (viewTag == 1) {
[allMonthButtonView setAlpha:.8];
[thisMonthButtonView setAlpha:1];
if (allMonthIsActive == NO) {
return;
}
else{
[self reloadThisMonth];
[allMonthTable removeFromSuperview];
[self.view addSubview:thisMonthTable];
allMonthIsActive = NO;
}
}
else if(viewTag == 2){
if (!allMonthIsActive) {
allMonthIsActive = YES;
if (isLoadingAllMonth) {
return;
}
[self.view addSubview:HUD];
[allMonthTable setFrame:CGRectMake(4, 64, 312, 343)];
[allMonthTable setBackgroundColor:[self grayColor]];
[self.view addSubview:allMonthTable];
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
isLoadingAllMonth = YES;
[self reloadAllMonth];
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.allMonthTable reloadData]; // Or reload tableView
[HUD hide:YES];
});
});
}
}
}
代码:reloadAllMonth
-(void)reloadAllMonth{
UIFont *titleFont = [UIFont fontWithName:@"Cochin" size:14.0];
UIFont *detailFont = [UIFont fontWithName:@"Cochin" size:18.0];
[[MBProgressHUD HUDForView:self.view] setLabelFont:titleFont];
[[MBProgressHUD HUDForView:self.view] setDetailsLabelFont:detailFont];
[[MBProgressHUD HUDForView:self.view] setLabelText:@"Please wait"];
[[MBProgressHUD HUDForView:self.view] setDetailsLabelText:@"Cleaning Cache"];
if (allMonthData.count != 0) {
for (NSMutableArray *arr in allMonthData) {
[arr removeAllObjects];
}
[allMonthData removeAllObjects];
for (NSMutableArray *arr in allMonthDataNumbers) {
[arr removeAllObjects];
}
[allMonthDataNumbers removeAllObjects];
}
NSDate *rootDate = [NSDate dateWithTimeIntervalSinceReferenceDate:(10*365*24*60*60)];
int rootMonth = [[dataHandler getMonthNumber:rootDate] intValue];
NSMutableArray *allExp = [[NSMutableArray alloc]init];
NSNumber *currentMonth = [dataHandler getMonthNumber:[NSDate date]];
NSMutableArray *temp = [[NSMutableArray alloc]init ];
NSNumber *tempMonth = [NSNumber numberWithInt:(currentMonth.intValue+1)];
[temp removeAllObjects];
[[MBProgressHUD HUDForView:self.view] setDetailsLabelText:@"Updating Data..."];
while (tempMonth.intValue > rootMonth) {
tempMonth = [NSNumber numberWithInt:(tempMonth.intValue-1)];
temp = [NSMutableArray arrayWithArray:[dataHandler fetchAllExpensesForMonth:tempMonth]] ;
if (temp.count != 0) {
[allExp addObject:temp];
}
}
allMonthData = allExp;
if (!allMonthDataNumbers) {
allMonthDataNumbers = [[NSMutableArray alloc]init];
}
[[MBProgressHUD HUDForView:self.view] setDetailsLabelText:@"Updating Balances..."];
for (NSArray *current in allMonthData) {
Expense *exp = [current objectAtIndex:0];
NSNumber *monthNumber = exp.month;
double budget = 0;
double spent = 0;
double balance = 0;
int count = 0;
double avgDayBal = 0;
for (Expense *exp in current) { // iterate this month
if (exp.expenseType.boolValue == 0) { // all day type expensees
spent = spent+exp.value.doubleValue;
count ++;
}
else if (exp.expenseType.boolValue == 1) {
budget = budget+exp.value.doubleValue;
}
}
balance = budget+spent;
avgDayBal = balance/[dataHandler numberOfDaysInMonthForMonth:monthNumber];
NSMutableArray *temp = [[NSMutableArray alloc]init];
[temp addObject:monthNumber];
[temp addObject:[NSNumber numberWithDouble:budget ]];
[temp addObject:[NSNumber numberWithDouble:spent ]];
[temp addObject:[NSNumber numberWithDouble:balance ]];
[temp addObject:[NSNumber numberWithInt:count ]];
[temp addObject:[NSNumber numberWithDouble:avgDayBal ]];
[allMonthDataNumbers addObject:temp];
}
NSNumber *day = [dataHandler getDayNumber:[NSDate date] ];
[[allMonthDataNumbers lastObject] addObject:day];
NSLog(@"We have %d month", [allMonthDataNumbers count]);
[[MBProgressHUD HUDForView:self.view] setDetailsLabelText:@"Updating Interface..."];
[allMonthTable reloadData];
isLoadingAllMonth = NO;
}
代码:reloadThisMonth
-(void)reloadThisMonth{
[dataHandler updateData];
if (!tableData) {
tableData = [[NSMutableArray alloc]initWithCapacity:31];
}
for (NSMutableArray *temp in tableData) {
[temp removeAllObjects];
}
[tableData removeAllObjects];
for (int j = 0; j < 31; j++) { //fill with 31 empty mutuable arrays
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
[tableData addObject:tempArray];
}
for (Expense *exp in dataHandler.allMonthExpenses) {
if (exp.expenseType.boolValue == 0) {
[[tableData objectAtIndex:(exp.day.intValue-1)]addObject:exp];
}
}
int countDayExp = 0;
for (NSMutableArray *arr in tableData) {
countDayExp = countDayExp + arr.count;
}
if (countDayExp == 0) {
hasDayExpenses = NO;
}
else{
hasDayExpenses = YES;
}
[thisMonthTable reloadData];
[thisMonthTable setBackgroundColor:[self grayColor]];
}
有人看到我哪里错了吗?或者还有什么问题?两个表都显示正常。如果我在加载第二个 View 时不与应用程序交互,则一切正常。有什么想法吗?
更新:
显然,两个线程在同时捕获同一个 fethroutine 时会发生冲突 - 这是应用“挂起”时暂停调试状态的屏幕截图。如果我打开另一个需要相同获取例程的选项卡,应用程序会挂起。如果我在挂起状态下调试和暂停,它会在获取例程中显示一行。这是我第一次使用线程 - 我真的很感激关于如何避免这种冲突的一些意见:/
最佳答案
我在另一个线程中运行任务时遇到了与 MBProgressHUD 类似的问题。我解决它的方法是到处使用 *HUD 属性而不是局部变量。看起来您在某些地方使用局部变量而在其他地方使用实例变量。
@property (strong, nonatomic) MBProgressHUD *HUD;
然后像这样使用它:
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.delegate = self;
在另一个线程中执行您的代码,然后使用 GCD 调用主线程以隐藏它并移除 HUD:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//Your Code to execute in the background
dispatch_async(dispatch_get_main_queue(), ^(void) {
//Code here to update stuff on main thread
//Example: hide hud or change hud label
HUD.labelText = @"Foo Done, Bar started"; //change label
[HUD hide:YES]; // or hide HUD
[self.tableView reloadData]; // Or reload tableView
});
});
和 MBProgressHUD 代表:
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
HUD = nil;
}
方法:
[HUD showWhileExecuting:@selector(reloadAllMonth) onTarget:self withObject:nil animated:YES];
和我遇到最多麻烦的地方一样。看起来 HUD 不知道您的 View 已更改并且认为选择器未完成并继续运行阻塞主线程。所以我摆脱了那个方法并使用实例变量 *HUD 和 GCD,每当我需要更新 HUD 的标签或隐藏/删除它时检索主线程,就像上面的代码一样。
关于iphone - 在 2 个 UITableViews 应用程序卡住之间交替,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9860801/