1

私は、2つの異なるテーブルビューを委任およびデータソースするViewControllerを使用しています。ユーザーが見たいものに応じて(ビュー内の特定の領域で「touchesBegan」を使用して切り替えが行われます。

ビューコントローラは、タブ付きアプリケーションの3つのサブコントローラの1つです。

テーブルビュー間の交代は、まさにフィンとして機能します。適切なデータやレイアウトなどを取得し、それらを何度でも変更できます。

最初のテーブルビューには難しいデータが含まれていないため、数ミリ秒で読み込まれます。

2番目のtableview2には、ロードに約2〜3秒かかるデータが含まれています(coredata内のエンティティの量によって異なります)。このデータが読み込まれ、tableview2が再描画されている間、MBProgressHUDが表示されます。これも機能します。

問題: table2の読み込み中に、hudが回転しているときに、tabbarcontrollerを操作すると、アプリがhudを「フリーズ」し、hudが無限に長く実行され、userinteractinoが無効になります。また、クリックされたタブは開きません。

コード:touchesBegan FUnction

    -(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]];

}

誰かが私がどこで間違っていたのかわかりますか?または他に何が問題になるのでしょうか?どちらの表も正常に表示されます。2番目のビューを読み込んでいるときにアプリを操作しないと、すべてが完全に機能します。何か案は?

更新

同じフェッチルーチンを同時に取得すると、明らかに2つのスレッドが衝突します。これは、アプリが「ハング」しているときに一時停止したデバッグ状態のスクリーンショットです。同じフェッチルーチンが必要な別のタブを開くと、アプリがハングします。ハング状態でデバッグして一時停止すると、フェッチルーチンの行が表示されます。スレッドを扱うのは初めてです-この衝突を回避する方法についていくつかの情報をいただければ幸いです:/

スレッドが衝突する

4

1 に答える 1

0

別のスレッドでタスクを実行しているときに、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はビューが変更されたことを認識せず、セレクターが終了していないと見なし、メインスレッドをブロックして実行を続けているようです。そこで、そのメソッドを取り除き、インスタンスVariable * HUDとGCDを使用して、上記のコードのようにHUDのラベルを更新したり、非表示/削除したりする必要があるときはいつでもメインスレッドを取得しました。

于 2012-03-25T17:50:16.497 に答える