2015-09-26 4 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, и она вернет вашу строку ячейки минус один для строк выше четырех.

Как это можно достичь в 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]) 
    } 

В примере ваша таблица вид программист должен был бы «просто знать», что они должны использовать specialNumberOfRowsInSection и specialCellForRowAtIndexPath в SpecialTableViewController, а не обычные звонки ... это не чистое решение для ввода-вывода.


Примечание: Я понимаю, вероятно, можно создать подкласс NSObject каким-то образом, чтобы переопределить сигналы (например, как описано here), но это не является языком решение.

ответ

2

github link -> может содержать более обновленное код

Чтобы ответить на этот вопрос: Это не возможно изменить стандартный поток функций между UITableViewController и UITableViewDataSource в виде подкласса.

Исходный код UIKit похож на большой черный ящик, который мы не можем видеть или изменять. (приложения будут отклонены, если вы это сделаете.) Чтобы сделать именно то, что вы хотите, вам нужно будет переопределить функции, вызывающие функции из UITableViewDataSource, чтобы они указывали на третью функцию, а не на функции протокола. Эта третья функция изменит основное поведение и вызовет функцию из UITableViewDataSource. Таким образом, все остальное останется прежним для других разработчиков.

Hack: Подкласс весь UITableviewController -> вам нужны сохраненные свойства. Таким образом, другие люди могут подклассифицировать ваш собственный класс, и они не смогут увидеть волшебство/беспорядок под капотом.

В приведенном ниже классе используется тот же стиль, что и обычный UITableViewController. Пользователи переопределяют методы, которые они хотят изменить. Поскольку эти методы используются внутри существующей функции, вы получаете измененную функциональность.

К сожалению, эти функции не могут быть закрыты.


Адаптер для indexPath хранит Bool и оригинальный indexPath. -> Это будет соответствовать вашим данным.

Новые вставленные ячейки получат индексную таблицу на основе раздела, в котором они созданы, и счетчика. -> Может быть полезно.


Обновление: Добавить х дополнительные строки после того, как у ряда


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». –

Смежные вопросы