2015-09-26 45 views
-1

想象一下,一個表格視圖控制器ExtraRowTableViewController,Swift,「子類」UITableView的數據源方法莫名其妙?

它總是插入一個額外的行後,(比方說)第三行。

在這個例子中

所以......

class SomeList:ExtraRowTableViewController 
override func numberOfSectionsInTableView(tableView: UITableView)->Int 
    { 
    return yourData.count ... say, 50 items 
    } 
override func tableView 
    (tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) 
             -> UITableViewCell 
    { 
    return yourData.cell ... for that row number 
    } 

ExtraRowTableViewController將「接管」,並實際上將返回51

有關的cellForRowAtIndexPath,它會「接管」,並在四排回到了自己的細胞,它會將您的單元格行N從0返回到3,並且它將返回您的單元格行減4以上的行。

這怎麼能在ExtraRowTableViewController中實現?

因此,SomeList的程序員根本不需要改變。

你會繼承UITableView,或數據源委託..或?


爲了澄清,一個例子使用情況而定,我們說,加入廣告,編輯字段,或者一些特殊的新聞,在第四排。 SomeList的程序員需要完全不做任何事情來達到這個目的是合適的,即它是以完全OO的方式實現的。


請注意,這是當然的,容易只需添加新的「替代品」的呼叫,你的表視圖將「只知道」來使用,而不是正常的呼叫。 (RMenke具有下面提供的這一個有用的完整的例子。)所以,

class SpecialTableViewController:UITableViewController 

func tableView(tableView: UITableView, specialNumberOfRowsInSection section: Int) -> Int 
    { 
    print ("You forgot to supply an override for specialNumberOfRowsInSection") 
    } 

func tableView 
    (tableView:UITableView, specialCellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell 
    { 
    print ("You forgot to supply an override for specialCellForRowAtIndexPath") 
    } 

override final func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    { 
    return self.specialNumberOfRowsInSection(section) + 1 
    } 

override final func tableView 
    (tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell 
    { 
    if indexPath.row == 4 
    { return ... the special advertisement cell ... } 
    if indexPath.row < 4 
    { return self.specialCellForRowAtIndexPath(indexPath) 
    if indexPath.row > 4 
    { return self.specialCellForRowAtIndexPath([indexPath.row - 1]) 
    } 

在您的表視圖程序員必須「只知道」,他們必須在SpecialTableViewController使用specialNumberOfRowsInSection和specialCellForRowAtIndexPath而不是通常的呼叫的例子...這不是一個乾淨的,簡單的面向對象解決方案。


注:我很欣賞你也可能以某種方式覆蓋信號NSObject的子類(如討論here),而不是一種語言的解決方案。

回答

2

github link - >可能包含更多更新的代碼

要回答這個問題:這是不可能覆蓋在子類的形式的UITableViewController和UITableViewDataSource之間的功能的標準流程。

UIKit源代碼就像一個我們看不到或改變的大黑盒子。 (如果你這樣做,應用程序將被拒絕。)爲了完成你想要的操作,你需要重寫從UITableViewDataSource調用函數的函數,以便它們指向第三個函數而不是協議函數。這第三個函數會改變基本行爲並從UITableViewDataSource觸發函數。這樣,對於其他開發者來說,這一切都將保持不變。

黑客:子類的整個UITableviewController - >你需要存儲的屬性。這樣,其他人可以繼承你的自定義類,並且他們不會看到任何魔法/混亂之下。


下面的類使用與常規UITableViewController相同的樣式。用戶重寫他們希望改變的方法。由於這些方法在現有函數內部使用,因此您將獲得更改的功能。

不幸的是,將這些功能標記爲私有是不可能的。


indexPath的適配器存儲Bool和原始indexPath。 - >這將對應您的數據。

新插入的單元格將根據它們創建的部分和計數器獲取indexPath。 - >可能有用。


更新:加入後X多餘的行y行


class IATableViewController: UITableViewController { 

    private var adapters : [[cellAdapter]] = [] 

    private struct cellAdapter { 
     var isDataCell : Bool = true 
     var indexPath : NSIndexPath = NSIndexPath() 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    func cellIdentifier(tableView: UITableView, isDataCell: Bool) -> String { 
     return "Cell" 
    } 


    func numberOfSections(tableView: UITableView) -> Int { 
     return 0 
    } 

    func numberOfRowsInSection(tableView: UITableView, section: Int) -> Int { 
     return 0 
    } 

    func insertXRowsEveryYRows(tableView: UITableView, section: Int) -> (numberOfRows:Int, everyYRows:Int)? { 
     //(numberOfRows:0, everyYRows:0) 
     return nil 
    } 

    func insertXRowsAfterYRows(tableView: UITableView, section: Int) -> (numberOfRows:Int, afterYRows:Int)? { 
     //(numberOfRows:0, afterYRows:0) 
     return nil 
    } 

    internal override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     // #warning Incomplete implementation, return the number of sections 
     let sections = numberOfSections(tableView) 

     adapters = [] 

     for _ in 0..<sections { 
      adapters.append([]) 
     } 

     return sections 
    } 

    internal override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     // #warning Incomplete implementation, return the number of rows 
     let rows = numberOfRowsInSection(tableView, section: section) 

     adapters[section] = [] 

     for row in 0..<rows { 
      var adapter = cellAdapter() 
      adapter.indexPath = NSIndexPath(forRow: row, inSection: section) 
      adapter.isDataCell = true 
      adapters[section].append(adapter) 
     } 

     insertion(tableView, section: section) 

     return adapters[section].count 
    } 

    private func insertion(tableView: UITableView, section: Int) { 

     if let insertRowEvery = insertXRowsEveryYRows(tableView, section: section) { 
      let insertionPoint = insertRowEvery.everyYRows 
      let insertionTimes = insertRowEvery.numberOfRows 

      var counter = 0 

      var startArray = adapters[section] 
      var insertionArray: [cellAdapter] = [] 

      while !startArray.isEmpty { 

       if startArray.count > (insertionPoint - 1) { 

        for _ in 0..<insertionPoint { 
         insertionArray.append(startArray.removeFirst()) 
        } 
        for _ in 0..<insertionTimes { 
         var adapter = cellAdapter() 
         adapter.indexPath = NSIndexPath(forRow: counter, inSection: section) 
         adapter.isDataCell = false 
         insertionArray.append(adapter) 
         counter += 1 
        } 
       } else { 
        insertionArray += startArray 
        startArray = [] 
       } 
      } 

      adapters[section] = insertionArray 

     } 
     else if let insertRowAfter = insertXRowsAfterYRows(tableView, section: section) { 

      let insertionPoint = insertRowAfter.afterYRows 
      let insertionTimes = insertRowAfter.numberOfRows 

      if adapters[section].count > (insertionPoint - 1) { 

       for i in 0..<insertionTimes { 

        var adapter = cellAdapter() 
        adapter.indexPath = NSIndexPath(forRow: i, inSection: section) 
        adapter.isDataCell = false 
        adapters[section].insert(adapter, atIndex: insertionPoint) 

       } 
      } 
     } 
    } 


    func insertionCellForRowAtIndexPath(tableView: UITableView, cell: UITableViewCell, indexPath: NSIndexPath) -> UITableViewCell { 

     return cell 
    } 



    func dataCellForRowAtIndexPath(tableView: UITableView, cell: UITableViewCell, indexPath: NSIndexPath) -> UITableViewCell { 

     return cell 

    } 


    internal override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

     let adapter = adapters[indexPath.section][indexPath.row] 

     let identifier = cellIdentifier(tableView, isDataCell: adapter.isDataCell) 
     let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) 

     switch adapter.isDataCell { 
     case true : 
      return dataCellForRowAtIndexPath(tableView, cell: cell, indexPath: adapter.indexPath) 
     case false : 
      return insertionCellForRowAtIndexPath(tableView, cell: cell, indexPath: adapter.indexPath) 
     } 
    } 
} 
+0

你基本上提出有新的功能,和人民書寫IATableViewController的子類必須知道使用這些新功能,而不是通常的? – Fattie

+0

@JoeBlow對第二部分是肯定的。不幸的是,默認函數來自的TableViewDataSource是一個協議,我們不能將存儲的屬性添加到協議中。這意味着我們無法爲行/節號添加翻譯器/適配器。你需要那樣的東西。否則,您從中獲得的indexPath,例如選擇一行將不再匹配您的數據。看看github。這比現在看起來簡單得多,因爲你只是覆蓋了新的功能。其他一切都是隱藏的。 –

+0

@JoeBlow回答第一條評論。無論你在任何地方添加多少行/部分,你總會需要一個翻譯器(如上所述)。顯然你可以改變上面的代碼,只在最後或「4」處添加一行。 –