你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS數據、界面分開設計模式遇到的一個問題

iOS數據、界面分開設計模式遇到的一個問題

編輯:IOS開發綜合

我們習慣在開發中把數據和界面分開實現,這種方式比較好,只需要在數據和界面中同時依賴一個數據結構即可,這種做法對於解藕是一個不錯的方式。
但是有一些細節的地方可能會導致我們遇到一些很難查找的bug,比如我們之前遇到的一個問題,現在分享給大家。

先來描述一下問題:我們在UITableView中加入了一個向下拖動刷新數據的控件,控件是EGORefreshTableHeaderView。拖動後,我們就使用ASIHttpRequest刷新數據,但是在拖動幅度大一些時,ASIHttpRequest請求發出後就直接崩潰了,而且看棧也看不出崩在哪。

數據請求代碼如下:

[cpp] 
- (void)startGetNewsListData 
 

 
    //newsDataArray是一個成員變量,用於取到數據後用於postNotificationName,給UITableView使用到 
 
    if (nil !=newsDataArray &&newsDataArray.count >0) 
 
    { 
 
        [newsDataArrayremoveAllObjects]; 
 
    } 
 
    NSString *strURL = @"*****";//此處需要填入url的地址字符串 
 
    NSURL *url = [NSURLURLWithString:strURL]; 
 
    ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url]; 
 
    //設定委托,委托自己實現異步請求方法 
 
    [request setDelegate : self ]; 
 
    // 開始異步請求 
 
    [requeststartAsynchronous ];//執行完這句後,就直接崩潰了 
 
    //[request release]; 
 

 
- ( void )requestFinished:( ASIHTTPRequest *)request 
 

 
    NSString *strRequest = [request responseString]; 
 
    SBJsonParser *parser = [[SBJsonParseralloc]init];   
 
    NSDictionary *json = [parser objectWithString:strRequest error:nil]; 
 
    int nCounts = [[json objectForKey:@"counts"]intValue]; 
 
    NSArray *activities = [json objectForKey:@"news"];  
 
    for (int i =0; i< nCounts; i++) 
 
    { 
 
        NSDictionary *dictSummary = [activitiesobjectAtIndex:i]; 
 
        NewsData *data = [[NewsDataalloc]init]; 
 
        data.ID = [dictSummary objectForKey:@"id"]; 
 
        ......//填入NewsData的各成員變量 
 
        [newsDataArray addObject:data]; 
 
        [data release]; 
 
    } 
 
    ......//其他邏輯 
 
    [[NSNotificationCenterdefaultCenter]postNotificationName:@"GetNewsListDataDone"object:newsDataArray];  
 


猜測調試過程如下:

1)開始猜測問題是EGORefreshTableHeaderView大幅拖動導致的,於是把ASIHttpRequest請求數據注釋掉,再次大幅拖動,程序沒崩。

2)那問題一定出在ASIHttpRequest請求部分,猜測會不會是請求在子線程中做的,導致的問題,調試一下,發現請求還是在主線程中,所以也排除了這種情況。

3)一開始一直以為是ASIHttpRequest出的問題,所以精力一直放在他上面。但是後來調了1個小時,查了ASIHttpRequest的使用說明,也沒查到什麼疑點。

4)實在是沒辦法了,祭出屠龍寶刀:開始代碼分段注釋,運行看結果。問題出在

[cpp] 
- (void)startGetNewsListData函數,所以從這邊開始:注釋 
 
if (nil != newsDataArray && newsDataArray.count > 0) 
 
    { 
 
        [newsDataArray removeAllObjects]; 
 
    } 

這段,運行,結果正常了,http請求也能收到返回的結果了,天哪,要是早點采用這種方法,也就不用之前嘗試的1個小時了。開始分析為什麼,newsDataArray前面說了,這個數據是會通過
[cpp]
[[NSNotificationCenter defaultCenter] postNotificationName:@"GetNewsListDataDone" object:newsDataArray]; 發送,給UITableView中使用,看接收稱處的代碼: 
 
...... 
 
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(onGetNewsListDataSuccess:)name:@"GetNewsListDataDone"object:nil]; 
 
...... 
 
- (void)onGetNewsListDataSuccess:(NSNotification*)notify 
 

 
    NSMutableArray *receiveArray = [notify object]; 
 
    ...... 
 
NSInteger nNewsCount = receiveArray.count; 
 
if (nNewsCount >0) 
 
    { 
 
       m_arrNews = receiveArray;//可以看到下面使用這個成員變量m_arrNews 

 
    [m_TableView reloadData]; 
 
    ...... 
 

 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
 

 
    static NSString* strCellIdentifier =@"NewsCellIdentifier"; 
 
    NewsListCell* cell = (NewsListCell *)[tableViewdequeueReusableCellWithIdentifier:strCellIdentifier]; 
 
    if (cell == nil) 
 
    { 
 
       ...... 
 
    } 
 
    NSInteger row = indexPath.row; 
 
    if (m_arrNews) 
 
    { 
 
//可以看到UITableView中的數據就是使用的m_arrNews 
 
        NewsData* data = (NewsData *)[m_arrNewsobjectAtIndex:row]; 
 
        cell.Title = data.Title; 
 
        ...... 
 
    } 
 
    ...... 
 
    return cell; 
 

看完這些,我也知道問題出在什麼地方了,我們知道,在UITableView中,在用戶拖動cell,有cell 的indexPath發生變化時,就會觸發這個函數:

[cpp] view plaincopy
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)這個函數中我們用到了m_arrNews,而m_arrNews又是通過 
 
NSMutableArray *receiveArray = [notify object]; 
 
    ...... 
 
   m_arrNews = receiveArray; 


這麼來的,這裡面全是使用的指針拷貝,原來問題就是這個:淺拷貝,先來解釋一下深拷貝和淺拷貝:
   (1)深拷貝,就是新拷貝一塊內存交給對象使用。會拷貝整個數據到新的地址,老的拷貝源改變和目標地址的數據就無關了。

   (2)淺拷貝,就是覺得拷貝內存太浪費,直接給你我的地址吧。當然這個地址和拷貝源相同,只要拷貝源發生改變,這個目標地址中的數據也會變化。

問題就明顯了[newsDataArray removeAllObjects];導致了UITableView中的數據源發生變化,而大幅度拉動,導致了UITableView中數據刷新,進入

[cpp] 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *),數據失效,導致崩潰,那解決問題也很簡單,使用深拷貝就可以了。 
 
- (void)onGetNewsListDataSuccess:(NSNotification*)notify 
 

 
    //NSMutableArray *receiveArray = [notify object];改成 
 
NSMutableArray *receiveArray = [[NSArrayalloc]initWithArray:[notifyobject]]; 
 
    ...... 
 
NSInteger nNewsCount = receiveArray.count; 
 
if (nNewsCount >0) 
 
    { 
 
       m_arrNews = receiveArray;//可以看到下面使用這個成員變量m_arrNews 

 
    [m_TableViewreloadData]; 
 
    ...... 
 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved