2012-03-25 5 views
1

Ich arbeite mit einem ViewController, der & Datenquellen 2 verschiedene Tabellenansichten delegiert. nach dem, was wünscht der Benutzer (toggeln geschieht mit ‚touchesBegan‘ für bestimmte Bereiche in der Ansicht zu sehen.wechselnd zwischen 2 UITableViews Application Freeze

Der Viewcontroller eines von 3 Subcontrollern eines Register Anwendung ist.

Der Wechsel zwischen dem Tableviews funktioniert fin in wenigen Millisekunden. bekomme ich die richtigen Daten, Layout, etc, und ich kann so oft wie ich.

die erste Tableview enthält nicht schwierig, Daten will zwischen ihnen ändern, damit es

den zweiten geladen wird. tableview2 enthält Daten, die etwa 2-3 Sekunden zum Laden benötigen (abhängig von der Menge) von Entitäten in Coredata). während diese Daten geladen werden & die TableView2 Neuzeichnungen ich eine MBProgressHUD zeigen. das funktioniert auch.

Problem: wenn i interagieren mit dem TabBarController während table2 & Beladung ist die HUD dreht, die app 'friert' das HUD läuft infinitly lang und jede userinteractino ist deaktiviert. Auch der angeklickte Tab konnte nicht geöffnet werden.

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]; 
       }); 

      }); 
     } 
    } 

} 

Code: 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; 

} 

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

} 

sieht jemand wo ich falsch gelaufen bin? oder was sonst könnte das Problem sein? beide Tabellen zeigen gut. Wenn ich beim Laden der zweiten Ansicht nicht mit der App interagiere, funktioniert alles perfekt. irgendwelche Ideen?

Update:

offenbar zwei Fäden miteinander kollidieren, wenn die gleiche fetchroutine zugleich grapping - hier ist ein Screenshot von einem Zustand angehalten debug, während die App ‚gehängt‘. Wenn ich eine andere Registerkarte öffne, die die gleiche Abrufroutine benötigt, hängt die App. wenn ich debugge & pause im aufgehängten zustand zeigt es mir eine linie in der abholroutine. es ist das erste Mal, dass ich mit Themen arbeiten - ich würde wirklich etwas Eingang zu schätzen weiß, wie man diese Kollision zu vermeiden:/

threads colliding

+0

Es tut uns leid, haben Sie keine Zeit, Ihren Code für eine richtige Antwort zu lesen, aber es sieht nicht so aus, als ob Sie GCD verwenden. Wenn Sie den Code werfen, der die andere Tabelle in einen separaten Thread lädt, kann der Hauptthread die Benutzeroberfläche mit Priorität bearbeiten und Sie würden wahrscheinlich jede Verzögerung loswerden. –

+0

Über GCD zustimmen. Mein Vorschlag wäre, zu versuchen, die Ursache zu isolieren. Vielleicht ein kleines Projekt mit nur dieser komplexen Operation und einem einzigen Tisch. Habe auch nicht genau gelesen, aber es ist wahrscheinlich, dass die lange Operation hängt als das OS. – danh

+0

Ein weiterer Hinweis: Holen Sie es in den Zustand "hängen" in debug und pausieren Sie es. Sie könnten den Fehler sofort finden. – danh

Antwort

0

ich ein ähnliches Problem mit MBProgressHUD hatte während Aufgaben in einem anderen Thread ausgeführt wird. Die Art und Weise, wie ich es gelöst habe, war die Verwendung einer * HUD-Eigenschaft anstelle einer lokalen Variablen. Es sieht so aus, als ob Sie an einigen Stellen eine lokale Variable und in anderen eine Instanzvariable verwenden.

@property (strong, nonatomic) MBProgressHUD *HUD; 

verwenden Sie es dann wie:

HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 
HUD.delegate = self; 

Führen Sie den Code in einem anderen Thread, rufen Sie dann den Haupt-Thread GCD mit, es zu verbergen und das HUD entfernen:

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 
       }); 

}); 

Und die MBProgressHUD Delegierter:

- (void)hudWasHidden:(MBProgressHUD *)hud { 
    // Remove HUD from screen when the HUD was hidded 
    [HUD removeFromSuperview]; 
    HUD = nil; 
} 

Die Methode:

[HUD showWhileExecuting:@selector(reloadAllMonth) onTarget:self withObject:nil animated:YES]; 

ist das gleiche wie wo ich in den meisten Schwierigkeiten geriet. Es sieht so aus, als ob das HUD nicht weiß, dass Ihre Ansicht geändert wurde, und denkt, dass der Selektor nicht fertig ist und weiterhin den Hauptthread blockiert. Also habe ich diese Methode losgeworden und die Instanzvariable * HUD und GCD benutzt, um den Hauptthread immer dann zu holen, wenn ich die HUD-Beschriftung aktualisieren oder verstecken/entfernen wollte, wie im obigen Code.

+0

Ich habe meinen Code von BerührungenBegun in der Frage aktualisiert. Das Problem bleibt immer noch das gleiche ... es hängt in der Abrufroutine, nachdem versucht wurde, eine weitere Registerkarte zu öffnen, die dieselbe Abrufroutine verwendet. –

+0

ist es möglich, den versendeten Thread zu beenden, wenn die Tableiste gedrückt wird? –