注意:我知道这是一个重新发布的问题;我几天前发布了相同的问题,而且,可以理解,它是关闭的。我编辑了这个问题以添加一些相关的片段,但是问题没有重新打开,所以我在这里重新发布。如果这不是正确的方法,让我知道!
我有一个有两种模式的应用程序,每种模式的设置屏幕都略有不同(其中一种模式中有一个额外的部分,行数上的一些差异,不同的用户默认键等等)。在过去,我用一大堆switch和if语句实现了这一点,但为了使事情更易于维护,我正在研究如何将这两种模式分成各自独立的类。最初,我考虑创建两个独立的UITableViewController
子类,但是我很难考虑如何使用故事板等。然后我想使用两个独立的UITableView
子类,并根据viewDidLoad
中的模式选择要显示的子类。
不过,我对这种方法有意见。我把它设置成控制器的cellForRow
方法调用TableView的cellForRow
方法,但这就是问题所在。当尝试执行dequeueReusableCell
时,应用程序会崩溃,并在该行出现永远模糊的“EXC_BAD_INSTRUCTION
”错误。
以下是一些相关代码:
视图控制器.swift
...
override func viewDidLoad()
{
super.viewDidLoad()
...
tableView = SRScaleSettingsTableView()
}
...
override func tableView(_ tableView: UITableView?, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return (tableView?.cellForRow(at: indexPath))!
}
SRScaleSettingsTableView.swift设置
override func cellForRow(at indexPath: IndexPath) -> UITableViewCell?
{
...
switch indexPath.section
{
case 0:
...
let switchCell = dequeueReusableCell(withIdentifier: "SwitchCell") as! SRSwitchCell
^ Debugger breaks on that line with EXC_BAD_INSTRUCTION
...
return switchCell
...
}
}
有什么想法会导致这种情况吗?我的方法是正确的吗?有更好的方法吗?
最佳答案
您可以保留一个UITableView类(您可能根本不需要子类UITableView)和一个UIViewController子类。创建两个实现UITableViewDataSource
协议的不同类(也可能是UITableViewDelegate
)。这两个类可以以完全不同的方式实现各种委托/数据源方法(例如cellForRowAtIndexPath、numberOfRowsInSection、didSelectRow),以适应应用程序需要运行的不同模式。
protocol SettingsSource: UITableViewDelegate, UITableViewDataSource {
}
class SettingsSourceForModeA: NSObject, SettingsSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)...
}
class SettingsSourceForModeB: NSObject, SettingsSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)...
}
class SettingsViewController: UIViewController {
@IBOutlet tableView: UITableView!
var source: SettingsSource! {
didSet {
tableView.dataSource = source
tableView.delegate = source
}
}
override func viewDidLoad() {
super.viewDidLoad()
// whatever logic is appropriate to determine the mode
if appIsRunningInModeA() {
source = SettingsSourceForModeA()
} else {
source = SettingsSourceForModeB()
}
}
}
上面代码中的关键细节是SettingsViewController中的
source
变量,source
的值取决于应用程序运行的模式,它决定将哪个类用作表视图的数据源。故事板的设置很简单:一个场景设置viewcontroller,以及该场景中的一个stock UITableView。
注意,上面的
SettingsViewController
是UIViewController子类,而不是UITableViewController,因为数据源和委托协议是在单独的类中实现的,并在运行时确定。这将要求您手动连接故事板中的tableView
插座。但是,您不会在情节提要中连接UITableView的数据源和委托输出。相反,它是在运行时完成的,如上面的示例代码所示。注意,您可能不需要实现UITableViewDelegate,在这种情况下,您可以忽略上面示例代码中对UITableViewDelegate及其方法的引用。或者,如果您的UITableViewDelegate实现(例如didSelectRow方法)对于您的应用程序可以运行的两种模式是相同的,那么您可以在视图控制器类中实现它,在这种情况下,您可以将表视图的
delegate
出口直接连接到脚本中的视图控制器。