2014-02-21 47 views
2

如果您在行動畫期間不斷旋轉設備,此示例應用程序將在一段時間後崩潰。即使在行動畫中第一次旋轉時,我的真實應用程序也會崩潰。如何在insertRowsAtIndexPaths和設備旋轉期間保護tableview免遭崩潰

我應該如何保護我的應用程序免於在同步行動畫旋轉期間崩潰?在動畫完成之前,請不要建議禁止旋轉。數據源取決於網絡抓取,取決於用戶網絡可能需要1到30秒的任何時間,並且如果在發佈後立即看到應用在景觀中更好地觀看,則用戶想旋轉設備。

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 

     for (int i = 0; i < 30; i++) { 

      [NSThread sleepForTimeInterval:0.2]; // imitates fetching and parsing 
      [self.array addObject:[NSString stringWithFormat:@"cell number %d", i]]; 

      dispatch_async(dispatch_get_main_queue(), ^{ 

       // perform on main 
       NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
       [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      }); 
     } 
    }); 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return self.array.count; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; 

    // Configure the cell... 
    cell.textLabel.text = self.array[indexPath.row]; 

    return cell; 
} 

- (NSMutableArray *)array 
{ 
    if (!_array) { 
     _array = [[NSMutableArray alloc] init]; 
    } 
    return _array; 
} 

崩潰報告

2014-02-21 12:47:24.667 RowsAnimationRotate[2062:60b] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2903.23/UITableView.m:1330 
2014-02-21 12:47:24.673 RowsAnimationRotate[2062:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' 
+0

不知道設備的旋轉是否會影響它 – Injectios

+1

請參閱我的有關競爭條件的回答。旋轉是一個紅色的鯡魚,但可能會增加它發生的可能性,因爲改變了兩個線程上發生的事情的時間。 –

回答

8

你已經從根本上創造競爭條件。

問題是你在後臺線程中操作self.array,而self.tableView insertRowsAtIndexPaths正在主線程上運行,並將訪問self.array

所以在某些時候self.tableView insertRowsAtIndexPaths(或其他的tableView方法稱爲這樣的結果)是主線程上運行,在self.array期待一定數量的對象,但在後臺線程獲取那裏,又增加了一個.. 。

要解決你的模擬:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_async(queue, ^{ 

    for (int i = 0; i < 30; i++) { 

     [NSThread sleepForTimeInterval:0.2]; // imitates fetching and parsing 
     NSString *myNewObject = [NSString stringWithFormat:@"cell number %d", i]]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      // perform on main 
      [self.array addObject: myNewObject]; 
      NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
      [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
     }); 
    } 
}); 
+0

是的,它的確有用,謝謝了很多 –

0

你可以改變

dispatch_async(dispatch_get_main_queue(), ^{ 

       // perform on main 
       NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
       [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      }); 

有:

dispatch_async(dispatch_get_main_queue(), ^{ 

       // perform on main 
       NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
       [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
      }); 
+0

我發現唯一的區別是UITableViewRowAnimationNone,這沒有效果。該應用程序仍在崩潰。 –

+0

嘗試在dispatch_async結尾處重新加載你的tableview(queue,^ {in viewdidappear – chawki

0

可以請你嘗試同步你的模擬: -

它聲明周圍代碼塊的一個關鍵部分。在多線程代碼中,@synchronized保證在任何給定時間只有一個線程可以在塊中執行該代碼。

@synchronized(self.tableView) { 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 

     for (int i = 0; i < 30; i++) { 

      [NSThread sleepForTimeInterval:0.2]; // imitates fetching and parsing 
      [self.array addObject:[NSString stringWithFormat:@"cell number %d", i]]; 

      dispatch_async(dispatch_get_main_queue(), ^{ 

       // perform on main 
       NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 
       [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      }); 
     } 
    });          
           } 

希望有所幫助。請讓我知道如果我們必須採取另一種解決方案。

+0

我對@synchronized不瞭解,但是應用仍然與你的代碼一起崩潰Mike Pollard's建議實際工作 –

+0

從我所瞭解的@synchronized和鎖這不是一個解決方案。參考[這個答案](http://stackoverflow.com/questions/1215330/how-does-synchronized-lock-unlock-in -objective-c)的 –