2014-02-21 54 views
1

我開發iPhone應用程序在我從後臺服務器下載圖像,泰伯維滾動崩潰的應用程序

這裏查看我的應用程序,

當我Button 1點擊我正在取5數據從服務器還圖像,當用戶向上滾動時獲取數據後,我再次從服務器獲取新的5個數據,當用戶向上滾動時,我從服務器獲取新的5個數據等等。

擷取以下Button 1數據,如果我在Button 2點擊我取消我以前的Button 1螺紋和我對Button 2獲取新的5個數據,並再次滾動它獲取新的5個數據同按鈕1

但一段時間後,同時重新加載的tableview我的應用程序變得崩潰,並顯示:由於未捕獲的異常 'NSRangeException',原因 終止應用程序:' - [__ NSArrayM objectAtIndex:]:指數28超出範圍[0 .. 4]

這裏是我的代碼片段:

- (void)viewDidLoad 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     [self fetchDataForButton1]; 

     dispatch_async(dispatch_get_main_queue(), ^(void) { 


       [tableView reloadData]; 


     }); 
    }); 

} 


- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath 
{ 
if(it is last row then fetch new 5 data) 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

         //Code runs on background thread 
         [self LoadMoreData]; 

         dispatch_async(dispatch_get_main_queue(), ^(void) { 

          //Code here is run on the main thread 
          [_tblList reloadData]; 

         }); 
        }); 


     }else{ 
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

           [self beginBackgroundFetchTask]; 

           [self downloadImage_3:indexPath]; 

           [self endBackgroundFetchTask]; 
          }); 
     } 

} 


-(void)downloadImage_3:(NSIndexPath *)path{ 


     UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]]; 

     if (img) { 
      [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]]; 
     } 

     [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 


} 

- (void) beginBackgroundFetchTask 
{ 
    self.backgroundFetchTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [self endBackgroundFetchTask]; 
    }]; 
} 

- (void) endBackgroundFetchTask 
{ 
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundFetchTask]; 
    self.backgroundFetchTask = UIBackgroundTaskInvalid; 
    NSLog(@"ended BackgroundFetchTask"); 
} 

-(void)LoadMoreData 
{ 
    //Fetches new 5 data from server... 
} 
+0

嘗試調試應用程序,將斷點上的cellForRowAtIndexPath。看看陣列何時出界。你得到的錯誤是因爲數組在特定的indexPath.row上得到了空值。 – z22

+0

**原因:[__NSArrayM objectAtIndex:]:索引28超出界限[0..4] **,您嘗試訪問索引爲28的對象,但您的數組只有5個元素 – iNoob

+0

您是正確的傢伙,但是當我單擊我已經停止提取'按鈕1'的數據,並且我正在初始化我的數組並且再次獲取'按鈕2'的新數據,但是因爲它仍然提取'按鈕1'索引** 28 **的數據而發生崩潰是'按鈕1'我該如何阻止'按鈕1'的線程?點擊'按鈕2' – Krunal

回答

1

我認爲這個問題的表格說不定在[self downloadImage_3:indexPath];您的通話將被正確顯示dispatch_async當你在Button1dispatch_async塊沒有調用,那麼你點擊Button2,然後我猜msg_array被清空並填充新的5個對象,之後,dispatch_async塊被調用,path.row爲塊是28,而msg_array有5個新對象的新數組內容,然後崩潰。

您應該點擊另一個按鈕,這是不可能的dispatch_async,這樣你就可以在塊判決之前取消dispatch_async

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    [self beginBackgroundFetchTask]; 

    [self downloadImage_3:indexPath buttonIndex:index]; 

    [self endBackgroundFetchTask]; 
}); 

-(void)downloadImage_3:(NSIndexPath *)path buttonIndex:(int)buttonIndex{ 
    if(self.currentSelectIndex != buttonIndex) return; //skip reloadData if not same index 


     UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]]; 

     if (img) { 
      [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]]; 
     } 

     [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 

} 
+0

是的兄弟你是非常正確的同樣的事情發生在這裏。 – Krunal

+0

但問題是'downloadImage_3'正在爲每個單元格調用,如果我跳過相同的索引,那麼我將如何獲取滾動相同的索引圖像? – Krunal

+0

@Krunal。正如我的評論,如果不是相同的索引,請跳過reloadData,只需要關心數據刷新,而數據會影響當前選定的視圖。 – simalone

0

使用SDWebImage從服務器獲取圖像。

+0

你是正確的老兄,但是當我點擊'按鈕2'我已經停止提取'按鈕1'的數據,我正在初始化我的數組,並且再次爲'按鈕2'獲取新數據,但是發生崩潰,因爲它仍然提取'按鈕1'索引** 28 **是'按鈕1'我應該如何停止'按鈕1'的按鈕?點擊'按鈕2' – Krunal

0

由於您的日誌陣列只有5個計數,並且您按照indexpath.row提取數據,並且在此崩潰情況下爲。因此,您可能正在根據您的新陣列調整您的單元格索引路徑行,該陣列一次又一次地獲取滾動數據,但重複的步驟爲。

只需放置一個斷點並檢查您是否重置了[0 4]計數中的索引路徑行;

更新:

[[NSThread currentThread] populateDataInBackground]; 
+0

你是正確的傢伙,但是當我點擊'按鈕2'時我已經停止抓取'Button 1'的數據,我正在初始化我的數組,並且再次獲取'Button 2'的新數據,但是因爲它仍然獲取'Button 1'索引的數據** 28 **是'Button 1'點擊'按鈕,停止點擊'按鈕1'的線程2' – Krunal

0

這是因爲圖像花費時間,從服務器和小區負載時被分配得到的數據。

您需要爲其實施延遲加載。

Here是一個很好的教程。

+0

你是正確的傢伙,但是當我點擊'按鈕2'我已經停止提取'按鈕1'的數據,並且我正在初始化我的數組並且再次獲取'按鈕2'的新數據,但是發生崩潰,因爲它仍然抓取'按鈕1'索引** 28 **的數據是'按鈕1'的數據,我應該如何停止我的按鈕1的線程?點擊'按鈕2' – Krunal

0

禁用用戶交互,然後轉至頂部表:

[TableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; 

然後調用:

[TableView reloadData]; 

然後啓用userintercation。 希望能解決問題

+0

你是正確的傢伙,但是當我點擊'按鈕2'時,我已經停止提取'按鈕1'的數據,並且正在初始化我的數組並且再次爲'按鈕2'獲取新數據但是崩潰發生,因爲它仍然獲取'按鈕1'索引的數據** 28 **是'按鈕1'我應該如何停止我的'按鈕1'的線程?點擊'按鈕2' – Krunal

1

嘗試了這一點

1)使用SDWebImage從服務器

2)使用Pull Refresher功能爲獲取未來5個數據擷取圖片。

這將有助於在後臺獲取數據。

+0

你是正確的傢伙,但是當我點擊'按鈕2'時,我已經停止提取'按鈕1'的數據,並且我正在初始化我的數組並且再次爲'按鈕2'獲取新數據,但是崩潰發生,因爲它仍然獲取'按鈕1'索引的數據** 28 **是'按鈕1'我應該如何停止我的'按鈕1'的線程?點擊'按鈕2' – Krunal

+0

要停止線程請參閱此:http://stackoverflow.com/questions/11553863/objective-c-canceling-a-thread – Siddh

0

我不會從cellForRowAtIndexPath方法中獲取那樣的數據。這是用來顯示單元格。

相反,像這樣做:

  1. 目錄的原始數據。
  2. 當用戶滾動過去最後一個單元格時,顯示一個顯示加載符號的頁腳。同時
  3. 雖然頁腳顯示加載符號,然後才把調用fetchLoadData方法,等待
  4. 直到你不從服務器聽見,繼續顯示加載符號,不要開始添加新的細胞來爲任何事情做好準備,因爲你有可能無法獲得更多的數據,在這一點上你必須擺脫頁腳單元並讓用戶知道沒有更多的數據要檢索,或者如果有更多的數據要
    • 添加新5的數據對象到數據陣列
    • 更新數:顯示,然後通過執行在下列順序的設置你的下5個細胞使用numberOfRowsInSection委託方法在部分行
    • 你會發現,你的細胞,如果編碼正確,一旦你刷新使用[myTable reloadTable];