想象一下表视图控制器ExtraRowTableViewController
,
总是在(比方说)第三行之后插入一个额外的行。
所以在这个例子中......
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] )
}
在示例中,您的表视图程序员必须“只知道”他们必须在SpecialTableViewController中使用specialNumberOfRowsInSection和specialCellForRowAtIndexPath而不是通常的调用......它不是一个干净的,插入式的OO解决方案。
注意:我感谢您可能以某种方式继承NSObject以覆盖信号(例如讨论过here),但这不是语言解决方案。
答案 0 :(得分:3)
github link - &gt;可能包含更多更新的代码
回答问题:无法以子类的形式覆盖UITableViewController和UITableViewDataSource之间的标准函数流。
UIKit源代码就像一个我们无法看到或改变的大黑盒子。 (如果你这样做,应用程序将被拒绝。)要完全按照你想要的方式做,你需要覆盖从UITableViewDataSource调用函数的函数,这样它们就指向第三个函数而不是协议函数。第三个函数将改变基本行为并从UITableViewDataSource触发函数。这样,对于其他开发者来说,它们都会保持不变。
Hack :对整个UITableviewController进行子类化 - &gt;你需要存储的属性。通过这种方式,其他人可以将您的自定义类子类化,并且他们不会看到任何魔术/混乱。
下面的类使用与常规UITableViewController相同的样式。用户覆盖他们希望改变的方法。因为这些方法在现有函数中使用,所以您可以获得更改的功能。
不幸的是,无法将这些功能标记为私有。
indexPath的适配器存储Bool
和原始indexPath。 - &GT;这将与您的数据相对应。
新插入的单元格将根据创建的部分和计数器获取indexPath。 - &GT;可能有用。
更新:在y行之后添加x个额外行
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)
}
}
}