чередовать 2 зависания приложения UITableViews - PullRequest
1 голос
/ 25 марта 2012

Я работаю с ViewController, который делегирует & источники данных 2 различных табличных представления.в зависимости от того, что пользователь хочет видеть (переключение происходит с помощью 'touchesBegan' для определенных областей в представлении.

Viewcontroller является одним из 3 субконтроллеров приложения с вкладками.

Чередование междуТабличные просмотры работают просто отлично. Я получаю правильные данные, расположение и т. д., и я могу переключаться между ними так часто, как хочу.

первое табличное представление не содержит сложных данных, поэтому оно загружается за несколько миллисекунд.

второй просмотр таблицы2 содержит данные, для загрузки которых требуется около 2-3 секунд (в зависимости от количества сущностей в coredata). Пока эти данные загружаются и перерисовывается таблица view2, я показываю MBProgressHUD. Это также работает.

Проблема: , если я взаимодействую с tabbarcontroller , пока table2 загружается и вращается жесткий диск, приложение "зависает", оно работает бесконечно долго, и любое пользовательское взаимодействие отключается.... а также нажатая вкладка не будет открыта.

CODE: 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]];

}

кто-нибудь видит, где я ошибся?или что еще может быть проблемой?обе таблицы показывают нормально.если я не взаимодействую с приложением во время загрузки второго представления, все работает отлично.какие-нибудь идеи?

update :

очевидно два потока сталкиваются при одновременном захвате одной и той же функции - вот скриншот приостановленного состояния отладки, пока приложение'подвешенный'.если я открою другую вкладку, которая нуждается в той же самой процедуре извлечения, приложение зависает.если я отлаживаю и делаю паузу в зависшем состоянии, это показывает строку в процедуре извлеченияЭто первый раз, когда я работаю с потоками - я был бы очень признателен за то, как избежать этого столкновения: /

threads colliding

1 Ответ

0 голосов
/ 25 марта 2012

У меня была похожая проблема с 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 или скрыть / удалить ее, как в приведенном выше коде.

...