2012-11-29 86 views
1

我試圖找出最好的方法添加和管理UISwitch我的UITableView的頭,並且至今對如何最好地使用表中的UISwitch我讀過幾個環節: hereherehere。這些鏈接演示瞭如何在單元格中使用UISwitch,而我在標題的自定義UIView中使用它們。這就是說,我寧願使用標籤來管理這些對象,但我不能弄清楚爲什麼viewWithTag的做法是行不通的。注意:我可以在運行時將UISwitch放入一個NSMutableArray中,並以這種方式管理它們,但我寧願不要這麼冗長,管理數組上的邊界衝突/索引或檢查nil列表,等等......我也不清楚我將如何使用IBOutlets來做到這一點。這就是我試圖使用標籤方法的原因。UISwitch和viewWithTag是零在numberOfRowsInSection

我的目標是使用開關摺疊/展開每個部分中的行,這就是爲什麼我認爲將UISwitches作爲子視圖標記並添加到我在viewForHeaderInSection中返回的UIView的原因。然後當我需要執行一些邏輯來摺疊單元格時,再重新引用它們。另外,在運行時,我可能有一個或多個部分,因此硬編碼標記號碼是不切實際的。下面是該方法的代碼:

假設:

#define kSwitchTagRange 2000 
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
{  
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)]; 

    // Add UISwitches and ensure that UISwitch doesn't already exist for this section... 
    UISwitch *switchView = (UISwitch*)[self.tableView viewWithTag:(kLayerSwitchTagRange + section)]; 

    if (switchView == nil) { 

     // Create switch 
     switchView = [[UISwitch alloc] init]; 
     double xOffset = self.tableView.bounds.size.width - switchView.frame.size.width; 
     switchView.frame = CGRectMake(xOffset, 
             7, 
             switchView.frame.size.width, 
             switchView.frame.size.height); 

     [switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; 

     // Should we tag the switch view? 
     switchView.tag = kSwitchTagRange + section; 
    } 

    // Add switch as subview 
    [view addSubview:switchView];  

    return view; 
} 

在switchChanged:我只是重新加載表的數據:

- (void)switchChanged:(id)sender { 

    [self.tableView reloadData]; 
} 

最後爲表的數據被重建我嘗試檢索UISwitch,並確定它的開/關狀態,那麼我如果OFF的部分,如果一些其他數行數返回0:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 

    NSInteger rowCount = 0; 

    UISwitch *switchView = (UISwitch*)[self.view viewWithTag:(kSwitchTagRange + section)]; 

    if (switchView != nil && switchView.isOn == NO) 
    { 
     rowCount = 0; 

    } 
    else 
    { 
     // Row count is something other than 0 
     rowCount = 3; 
    } 

    return rowCount; 
} 

不幸的是,這SWITCHVIEW始終是零。

我有一些猜測,但不能確定爲什麼發生這種情況。

  • 猜測1:當我重新加載表的數據時,我想添加的交換機的UIView被釋放。它不存在於內存中,因此無法通過標籤進行搜索。猜測2:我錯誤地將UISwitch添加到視圖對象中(在很多例子中,我已經看到對象添加到UITableViewCell的contentView,但是因爲我在viewForHeaderInSection:方法中發送了UIView,所以我不知道這些例子適用於此。addSubview應任何對象添加到樹。

誰能告訴我,爲什麼上面的viewWithTag方法將返回零?我傾向於競猜#1,但還沒有找到任何文件告訴我的自定義標題的UIView在任何時候被釋放,細胞被再次使用,但對於部分頭?

最後,我讀過this post和W hile關於標籤使用的建議是有道理的,它似乎完全不喜歡標籤方法。爲什麼不使用標籤,如果你沒有發現使用它們是混亂的,並且它們被智能地使用?爲什麼標籤功能甚至可用?

真的,我只是想知道爲什麼viewWithTag方法返回在我的案件爲零。

乾杯!

回答

1

我不知道爲什麼你總是viewWithTag返回nil,我認爲它可能與事實的看法都在某個點釋放做。

然而,標籤仍然可以工作,做你想做的,但你需要在你的模型對象跟蹤開關的值的屬性或鍵。您可以使用該標籤來確定交換機在其操作方法中的哪一部分,並適當更新模型。這就是我所做的。我的模型是字典的陣列,其中所述鍵「rowData」的值是與該部分中的所有數據的數組,並且鍵「switchValue」的值是一個NSNumber,0或1,表示該開關的狀態。所以,我的數據是這樣的:

2012-11-28 22:50:03.104 TableWithSwitchesInHeaderView[3592:c07] (
     { 
     rowData =   (
      One, 
      Two, 
      Three, 
      Four 
     ); 
     switchValue = 1; 
    }, 
     { 
     rowData =   (
      Red, 
      Orange, 
      Yellow, 
      Green, 
      Blue, 
      Violet 
     ); 
     switchValue = 1; 
    }, 
) 

這是我在相關表視圖委託和數據源的方法:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return self.theData.count; 
} 

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)]; 
    UISwitch *switchView = [[UISwitch alloc] init]; 
    double xOffset = self.tableView.bounds.size.width - switchView.frame.size.width; 
    switchView.frame = CGRectMake(xOffset,7,switchView.frame.size.width,switchView.frame.size.height); 
    [switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; 
    switchView.tag = kSwitchTagRange + section; 
    switchView.on = [[[self.theData objectAtIndex:switchView.tag - 101] valueForKey:@"switchValue"] boolValue]; 
    [view addSubview:switchView]; 
    return view; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 
    return 50; 
} 

- (void)switchChanged:(UISwitch *)sender { 
    NSMutableDictionary *dict = [self.theData objectAtIndex:sender.tag - 101]; 
    [dict setValue:[NSNumber numberWithBool:sender.isOn] forKey:@"switchValue"]; 
    [self.tableView reloadData]; 
} 


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    BOOL switchValue = [[self.theData[section] valueForKey:@"switchValue"] boolValue]; 
    if (switchValue) { 
     return [[self.theData[section] valueForKey:@"rowData"] count]; 
    }else{ 
     return 0; 
    } 

} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 
    cell.textLabel.text = [[self.theData[indexPath.section]valueForKey:@"rowData"]objectAtIndex:indexPath.row] ; 
    return cell; 
} 

我kSwitchTagRange被#define的爲101此代碼合作在開關關閉的任何部分摺疊行(實際上擺脫所有行)。

+0

感謝您的回覆。這實際上是我更喜歡來自Microsoft堆棧的一種方法(「將UI控件的屬性綁定到相應的數據模型對象的值」)。鑑於UISwitch可能不再可以引用,我可能會採用這種方法,但是在我之前我有一個哲學編程問題給你,但是:你如何看待[這裏]所述的觀點( http://doing-it-wrong.mikeweller.com/2012/08/youre-doing-it-wrong-4-uiview.html)? – Aaron

+0

(續....)它建議跟蹤UISwitch上的數據模型對象索引(在我們的例子中)而不是使用標籤。你對這種方法有什麼看法?矯枉過正?不關心? 「把它完成?」 :-)我也試圖完全理解.tag屬性的核心並且它是有用的。 – Aaron

+1

我覺得我在這個「過度殺傷」陣營。我不確定他的一些方法在處理表視圖中的視圖時會如何工作,這些視圖將不斷在滾動中創建和釋放。我寧願有一些類似於indexPathForSelectedRow的方法,類似於sectionForSelectedView,用於頁眉和頁腳視圖,但除非我錯過了某些東西,否則沒有,所以我們被一些更混亂的東西卡住了。 – rdelmar

0

從帖子here看來,viewForHeaderInSection返回的UIView被解除分配,必須重新創建(以及它的所有子視圖,包括我的UISwitch),而不是重新使用。我相信蘋果公司假設你的節標題比單元少得多,因此沒有提供檢索節標題的可重用機制。 @rdelmar提出的數據綁定方法似乎對這種情況有意義。

+0

這裏是[另一個相關的S.O.螺紋(http://stackoverflow.com/questions/7132613/viewforheaderinsection-creating-a-memory-leak),這表明您手動管理的標頭的子視圖,而不是一遍又一遍地重新創建。 – Aaron