将 UITableViewCell 中的 segue 推送到 Swift 中的 ViewController
Push segue from UITableViewCell to ViewController in Swift
我的 UITableViewCells 遇到了问题。我将我的 UITableView 连接到 API 以填充我的单元格。
然后我创建了一个函数,它获取 indexPath.row
来识别应该发送到 RestaurantViewController
的数组中的哪个 JSON-对象。
Link to my Xcode Project for easier debugging and problem-solving
下面是我的小代码片段如何将 "row-clicks" 设置为全局变量。
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
i = indexPath.row
}
这是我的 prepareForSegue()
函数,它应该将我的 push-segue 连接到 RestaurantViewController
。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
下面是我从 UITableViewCell
设置 segue 的方法
这是我的结果,我尝试单击这些单元格中的每一个,但我不会被推送到另一个单元格 viewController...我也没有收到错误。这里有什么问题?
Tried solutions that won't work
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let vc = segue.destinationViewController as RestaurantViewController
//let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
尝试在您的 cellForRow
方法中创建这样的单元格:
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
我注意到在你的故事板截图中,segue 正在将第一个原型单元格连接到 RestaurantViewController
。这个原型单元格看起来像是 "Basic" 风格的单元格,右边有一个披露指示器附件。但是看看你的应用程序的屏幕截图 运行。 table 填充的单元格似乎是 "Subtitle" 样式的单元格,右侧没有披露指示器附件。
无论您做什么,您的 segue 都不会触发的原因是 segue 仅配置为适用于特定的原型单元格,但是当您填充 table 时从未使用该原型单元格.无论您在 tableView:cellForRowAtIndexPath:
中做什么,您都没有使用您想要的原型单元格。
@Starscream 的想法是正确的,即使用正确的标识符将正确的单元格出队,并将其与 Interface Builder 中原型单元格的标识符相匹配。这样做之后你遇到的崩溃可能是因为上面评论中提到的先前问题。你在情节提要中的 segue 显然指向 UITableViewController
。 prepareForSegue:sender:
中的代码应该是 let vc = segue.destinationViewController as RestaurantViewController
,只要 RestaurantViewController
是 UITableViewController
的子 class。如果您尝试将其转换为 UINavigationController
,您将会崩溃。还要确保 Storyboard 中目标 UITableViewController
的 class 在 Identity Inspector 窗格中列为 RestaurantController
。如果您的程序编译时认为故事板只包含一个通用的 UITableViewController
,您将会崩溃。
再回到最初的问题,我不知道你是如何实现的tableView:cellForRowAtIndexPath:
,这可能很关键。也许不是那么简单。也许您计划在运行时处理许多原型单元或生成自定义单元。在这种情况下,一种简化此操作的方法是在用户点击单元格时以编程方式执行转场。不使用特定的原型单元,而是使 segue 成为从 "Restauranger nära mig" UITableViewController
到 RestaurantViewController
的连接。 (通过从第一个顶部的 Table View Controller 图标拖动到第二个主体,在 Interface Builder 中连接)。您必须在 Attributes Inspector 窗格中为这个 segue 提供一个标识符,以使其有用。假设它是 "toRestaurant"
。然后在 tableView:didSelectRowAtIndexPath:
方法的末尾,放入这行代码:self.performSegueWithIdentifier("toRestaurant", sender: self)
。现在无论在 table 中选择了哪个单元格,这个 segue 都会为你触发。
Dropbox link to stack3 directory
我很难理解为什么您的软件与标准的 2 级 table 视图结构有很大不同。所以我编写了一个简短的示例,您可以从这个 link 访问它。我还在下面包含了源代码。
该程序模仿您所拥有的(据我所知)。 Table 控制器 1 从 table 视图单元格转到 Table 控制器 2。我对 segue-ing 没有任何问题。请注意,我没有也不需要扩充 Storybook 来启动 segue。
我已将这两个控制器嵌入到导航控制器中。我的经验是省了很多设置导航的功夫
或者,我可以通过控制从屏幕顶部的第一个 TableViewController 符号拖动到第二个控制器并设置 segue。
我使用了全局变量 (selectedRow),但不推荐这样做。但是您可以轻松地使用 prepareForSegue 在 RestaurantTableViewController 中设置变量(我展示了一个示例)
- 最后,我建议检查连接检查器(针对第一个控制器中的 table 视图单元格)以确认第二个控制器有一个 segue。如果您正确地控制拖动,应该会出现确认提示以及连接检查器中的条目。
不幸的是我无法正确格式化代码
import UIKit
var selectedRow = -1
class TableViewController: UITableViewController {
var firstArray = ["Item1","Item2","Item3","Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = firstArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc = segue.destinationViewController as RestaurantTableViewController
// can write to variables in RestaurantTableViewController if required
vc.someVariable = selectedRow
}
}
import UIKit
class RestaurantTableViewController: UITableViewController {
var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"]
var someVariable = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = secondArray[indexPath.row]
if indexPath.row == selectedRow {
cell.textLabel!.text = cell.textLabel!.text! + " SELECTED"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
}
我一时兴起来这里,因为我现在才刚刚进入 swift,但我在 prepareForSegue()
中的做法是这样的:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
//notice I changed [i] to [index!.row]
vc.data = currentResponse[index!.row] as NSArray
}
}
在我看来,您正在调用 i 变量,它有点像 class 方法中的私有变量。您可以像@Syed Tariq 那样对 selectRow
变量进行操作,并将其设置在您的 class SomeController: UIViewController /*, maybe some more here? */ {
之上,然后在您的
中对变量进行签名
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
方法同上,但两种方法都应该很好用。
以下步骤应该可以解决您的问题。如果没有,请告诉我。
删除您的 tableView(tableView, didSelectRowAtIndexPath:)
实现。
使 RestaurantViewController
上的 data
具有类型 NSDictionary!
确定prepareForSegue
中选中的行:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = tableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
问题是您没有正确处理数据。
如果您查看 currentResponse
数组,您会发现它包含 NSDictionaries,但在您的 prepareForSegue
中,您尝试将 NSDictionary 转换为 NSArray,这会使应用程序崩溃。
将 RestaurantViewController
中的 data
变量更改为 NSDictionary 并将您的 prepareForSegue
更改为传递 NSDictionary
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = redditListTableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
对于Swift 5
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = self.tableView.indexPath(for: cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destination as! RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
我遇到了同样的问题,我发现解决方案是:
performSegueWithIdentifier("toViewDetails", sender: self)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cellnumber = procMgr.processos[indexPath.row].numero
println("You selected cell #\(indexPath.row)")
println(cellnumber)
performSegueWithIdentifier("toViewDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toViewDetails" {
let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails
}
}
您可能需要获取 UItableview 的选定单元格索引。下面的代码使用选定的单元格索引 (UItableview.indexPathForSelectedRow) 来获取数组的正确元素。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seguaVisitCardDetial" {
let viewController = segue.destinationViewController as! VCVisitCardDetial
viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!]
}
}
我也遇到过这个问题; UITableViewCell 的 segue 没有调用。
经过一番查找,我发现是因为我在“选择”字段中选择了“不选择”。
我的 UITableViewCells 遇到了问题。我将我的 UITableView 连接到 API 以填充我的单元格。
然后我创建了一个函数,它获取 indexPath.row
来识别应该发送到 RestaurantViewController
的数组中的哪个 JSON-对象。
Link to my Xcode Project for easier debugging and problem-solving
下面是我的小代码片段如何将 "row-clicks" 设置为全局变量。
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
i = indexPath.row
}
这是我的 prepareForSegue()
函数,它应该将我的 push-segue 连接到 RestaurantViewController
。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
下面是我从 UITableViewCell
设置 segue 的方法
这是我的结果,我尝试单击这些单元格中的每一个,但我不会被推送到另一个单元格 viewController...我也没有收到错误。这里有什么问题?
Tried solutions that won't work
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let vc = segue.destinationViewController as RestaurantViewController
//let vc = navigationController.topViewController as RestaurantViewController
vc.data = currentResponse[i] as NSArray
}
}
尝试在您的 cellForRow
方法中创建这样的单元格:
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)
我注意到在你的故事板截图中,segue 正在将第一个原型单元格连接到 RestaurantViewController
。这个原型单元格看起来像是 "Basic" 风格的单元格,右边有一个披露指示器附件。但是看看你的应用程序的屏幕截图 运行。 table 填充的单元格似乎是 "Subtitle" 样式的单元格,右侧没有披露指示器附件。
无论您做什么,您的 segue 都不会触发的原因是 segue 仅配置为适用于特定的原型单元格,但是当您填充 table 时从未使用该原型单元格.无论您在 tableView:cellForRowAtIndexPath:
中做什么,您都没有使用您想要的原型单元格。
@Starscream 的想法是正确的,即使用正确的标识符将正确的单元格出队,并将其与 Interface Builder 中原型单元格的标识符相匹配。这样做之后你遇到的崩溃可能是因为上面评论中提到的先前问题。你在情节提要中的 segue 显然指向 UITableViewController
。 prepareForSegue:sender:
中的代码应该是 let vc = segue.destinationViewController as RestaurantViewController
,只要 RestaurantViewController
是 UITableViewController
的子 class。如果您尝试将其转换为 UINavigationController
,您将会崩溃。还要确保 Storyboard 中目标 UITableViewController
的 class 在 Identity Inspector 窗格中列为 RestaurantController
。如果您的程序编译时认为故事板只包含一个通用的 UITableViewController
,您将会崩溃。
再回到最初的问题,我不知道你是如何实现的tableView:cellForRowAtIndexPath:
,这可能很关键。也许不是那么简单。也许您计划在运行时处理许多原型单元或生成自定义单元。在这种情况下,一种简化此操作的方法是在用户点击单元格时以编程方式执行转场。不使用特定的原型单元,而是使 segue 成为从 "Restauranger nära mig" UITableViewController
到 RestaurantViewController
的连接。 (通过从第一个顶部的 Table View Controller 图标拖动到第二个主体,在 Interface Builder 中连接)。您必须在 Attributes Inspector 窗格中为这个 segue 提供一个标识符,以使其有用。假设它是 "toRestaurant"
。然后在 tableView:didSelectRowAtIndexPath:
方法的末尾,放入这行代码:self.performSegueWithIdentifier("toRestaurant", sender: self)
。现在无论在 table 中选择了哪个单元格,这个 segue 都会为你触发。
Dropbox link to stack3 directory
我很难理解为什么您的软件与标准的 2 级 table 视图结构有很大不同。所以我编写了一个简短的示例,您可以从这个 link 访问它。我还在下面包含了源代码。
该程序模仿您所拥有的(据我所知)。 Table 控制器 1 从 table 视图单元格转到 Table 控制器 2。我对 segue-ing 没有任何问题。请注意,我没有也不需要扩充 Storybook 来启动 segue。
我已将这两个控制器嵌入到导航控制器中。我的经验是省了很多设置导航的功夫
或者,我可以通过控制从屏幕顶部的第一个 TableViewController 符号拖动到第二个控制器并设置 segue。
我使用了全局变量 (selectedRow),但不推荐这样做。但是您可以轻松地使用 prepareForSegue 在 RestaurantTableViewController 中设置变量(我展示了一个示例)
- 最后,我建议检查连接检查器(针对第一个控制器中的 table 视图单元格)以确认第二个控制器有一个 segue。如果您正确地控制拖动,应该会出现确认提示以及连接检查器中的条目。
不幸的是我无法正确格式化代码
import UIKit
var selectedRow = -1
class TableViewController: UITableViewController {
var firstArray = ["Item1","Item2","Item3","Item4"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = firstArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc = segue.destinationViewController as RestaurantTableViewController
// can write to variables in RestaurantTableViewController if required
vc.someVariable = selectedRow
}
}
import UIKit
class RestaurantTableViewController: UITableViewController {
var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"]
var someVariable = -1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return secondArray.count
}
let nameOfCell = "RestaurantCell"
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = secondArray[indexPath.row]
if indexPath.row == selectedRow {
cell.textLabel!.text = cell.textLabel!.text! + " SELECTED"
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
}
我一时兴起来这里,因为我现在才刚刚进入 swift,但我在 prepareForSegue()
中的做法是这样的:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toRestaurant"{
let navigationController = segue.destinationViewController as UINavigationController
let vc = navigationController.topViewController as RestaurantViewController
//notice I changed [i] to [index!.row]
vc.data = currentResponse[index!.row] as NSArray
}
}
在我看来,您正在调用 i 变量,它有点像 class 方法中的私有变量。您可以像@Syed Tariq 那样对 selectRow
变量进行操作,并将其设置在您的 class SomeController: UIViewController /*, maybe some more here? */ {
之上,然后在您的
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = indexPath.row
}
方法同上,但两种方法都应该很好用。
以下步骤应该可以解决您的问题。如果没有,请告诉我。
删除您的
tableView(tableView, didSelectRowAtIndexPath:)
实现。使
RestaurantViewController
上的data
具有类型NSDictionary!
确定
prepareForSegue
中选中的行:override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { if let cell = sender as? UITableViewCell { let i = tableView.indexPathForCell(cell)!.row if segue.identifier == "toRestaurant" { let vc = segue.destinationViewController as RestaurantViewController vc.data = currentResponse[i] as NSDictionary } } }
问题是您没有正确处理数据。
如果您查看 currentResponse
数组,您会发现它包含 NSDictionaries,但在您的 prepareForSegue
中,您尝试将 NSDictionary 转换为 NSArray,这会使应用程序崩溃。
将 RestaurantViewController
中的 data
变量更改为 NSDictionary 并将您的 prepareForSegue
更改为传递 NSDictionary
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = redditListTableView.indexPathForCell(cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destinationViewController as RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
对于Swift 5
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if let cell = sender as? UITableViewCell {
let i = self.tableView.indexPath(for: cell)!.row
if segue.identifier == "toRestaurant" {
let vc = segue.destination as! RestaurantViewController
vc.data = currentResponse[i] as NSDictionary
}
}
}
我遇到了同样的问题,我发现解决方案是:
performSegueWithIdentifier("toViewDetails", sender: self)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cellnumber = procMgr.processos[indexPath.row].numero
println("You selected cell #\(indexPath.row)")
println(cellnumber)
performSegueWithIdentifier("toViewDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toViewDetails" {
let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails
}
}
您可能需要获取 UItableview 的选定单元格索引。下面的代码使用选定的单元格索引 (UItableview.indexPathForSelectedRow) 来获取数组的正确元素。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seguaVisitCardDetial" {
let viewController = segue.destinationViewController as! VCVisitCardDetial
viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!]
}
}
我也遇到过这个问题; UITableViewCell 的 segue 没有调用。 经过一番查找,我发现是因为我在“选择”字段中选择了“不选择”。