ios 在 Swift 中将 segue 从 UITableViewCell 推送到 ViewController

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28323925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 04:40:30  来源:igfitidea点击:

Push segue from UITableViewCell to ViewController in Swift

iosiphoneuitableviewswiftuistoryboardsegue

提问by Hyman

I'm encountering problems with my UITableViewCells. I connected my UITableView to a API to populate my cells.

我的 UITableViewCells 遇到了问题。我将 UITableView 连接到 API 以填充我的单元格。

Then I've created a function which grabs the indexPath.rowto identify which JSON-object inside the array that should be sent to the RestaurantViewController.

然后我创建了一个函数,它抓取indexPath.row以识别数组中应该发送到RestaurantViewController.

Link to my Xcode Project for easier debugging and problem-solving

链接到我的 Xcode 项目以便于调试和解决问题

Here's how my small snippet looks for setting the "row-clicks" to a global variable.

这是我的小片段如何将“行点击”设置为全局变量。

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
     i = indexPath.row
}

And here's my prepareForSegue()function that should hook up my push-segue to the RestaurantViewController.

这是我的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
 }
}

And here's how I've set up my segue from the UITableViewCell

这是我如何从 UITableViewCell

Here's my result, I've tried to click every single one of these cells but I won't be pushed to another viewController...I also don't get an error. What is wrong here?

这是我的结果,我试图点击这些单元格中的每一个,但我不会被推送到另一个视图控制器......我也没有收到错误。这里有什么问题?

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
        }
    }

回答by ergoon

The problem is that you're not handling your data correctly. If you look into your currentResponseArray, you'll see that it holds NSDictionaries but in your prepareForSegueyou try to cast a NSDictionary to a NSArray, which will make the app crash.

问题是您没有正确处理数据。如果您查看您的currentResponseArray,您会看到它包含 NSDictionaries,但prepareForSegue您尝试将 NSDictionary 转换为 NSArray,这将使应用程序崩溃。

Change the datavariable in RestaurantViewControllerto a NSDictionary and change your prepareForSegueto pass a a NSDictionary

data变量更改RestaurantViewController为 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
        }
    }
}

回答by Tammo Freese

The following steps should fix your problem. If not, please let me know.

以下步骤应该可以解决您的问题。如果没有,请告诉我。

  1. Remove your tableView(tableView, didSelectRowAtIndexPath:)implementation.

  2. Make dataon RestaurantViewControllerhave type NSDictionary!

  3. Determine the selected row in 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
            }
        }
    }
    
  1. 删除您的tableView(tableView, didSelectRowAtIndexPath:)实现。

  2. 使dataRestaurantViewController有型NSDictionary!

  3. 确定 中的选定行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
            }
        }
    }
    

回答by Syed Tariq

Dropbox link to stack3 directory

Dropbox 链接到 stack3 目录

  1. I am having difficulty understanding why your software is much different than a standard 2 level tableview structure. So I coded a short example which you can access from this link. I have also included the sources code below.

  2. The program mimics what you have (as best as I understood it). Table Controller 1 segues to Table Controller 2 from the tableview cell. I had no issues with segue-ing. Notice that I do not have nor need to augment the Storybook to initiate the segue.

  3. I have embedded both the controllers in Navigation Controllers. My experience is that it saves a lot of effort to set up the navigation.

  4. Alternately, I could have control-dragged from the first TableViewController symbol on top of the screen to the second controller and set up the segue.

  5. I used a global variable (selectedRow) although it is not a recommend practice. But you just as easily use the prepareForSegue to set a variable in the RestaurantTableViewController (I show an example)

    1. Finally, I recommend checking the Connections Inspector (for the table view cell in the first controller) to confirm that there is a segue to the second controller. If you control-dragged properly there should be confirmation prompt as well as an entry in the Connections Inspector.
  1. 我很难理解为什么您的软件与标准的 2 级 tableview 结构有很大不同。所以我编写了一个简短的示例,您可以从此链接访问。我还包括下面的源代码。

  2. 该程序模仿您所拥有的(尽我所知)。表控制器 1 从表视图单元格转到表控制器 2。我对 segue-ing 没有任何问题。请注意,我没有也不需要扩充 Storybook 来启动 segue。

  3. 我已将两个控制器嵌入到导航控制器中。我的经验是,它可以节省很多设置导航的工作量。

  4. 或者,我可以将控件从屏幕顶部的第一个 TableViewController 符号拖动到第二个控制器并设置转场。

  5. 我使用了一个全局变量(selectedRow),虽然它不是推荐的做法。但是您可以轻松地使用 prepareForSegue 在 RestaurantTableViewController 中设置一个变量(我举了一个例子)

    1. 最后,我建议检查 Connections Inspector(对于第一个控制器中的表格视图单元格)以确认第二个控制器有一个 segue。如果您正确地控制拖动,应该有确认提示以及连接检查器中的条目。

Unfortunately I just cant get the code properly formatter

不幸的是,我无法正确获取代码格式化程序

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

}

}

回答by Christopher Whidden

I noticed that in your screenshot of your storyboard, the segue is connecting the first prototype cell to the RestaurantViewController. This prototype cell looks like it's the "Basic" style of cell with a disclosure indicator accessory on the right. But look at the screenshot of your app running. The table is being populated with cells that appear to be the "Subtitle" style of cell without a disclosure indicator accessory on the right.

我注意到在你的故事板截图中,segue 将第一个原型单元连接到RestaurantViewController. 这个原型单元看起来像是“基本”样式的单元,右侧有一个显示指示器附件。但是看看你的应用程序运行的屏幕截图。表格中填充的单元格看起来是“副标题”样式的单元格,右侧没有显示指示器附件。

The reason that your segue is never firing no matter what you do is that the segue is only configured to work for a specific prototype cell, but that prototype cell is never being used when you populate the table. Whatever you're doing in tableView:cellForRowAtIndexPath:, you're not using the prototype cell that you want.

无论您做什么,您的 segue 都不会触发的原因是,segue 仅配置为适用于特定的原型单元格,但在填充表格时从不使用该原型单元格。无论你在做什么tableView:cellForRowAtIndexPath:,你都没有使用你想要的原型单元。

@Starscream has the right idea dequeueing the right cell with the right identifier and matching it with the identifier of the prototype cell in Interface Builder. The crash that you're getting even after doing that might be because of the previous problem mentioned in the comments above. Your segue in the storyboard is clearly pointing to a UITableViewController. Your code in prepareForSegue:sender:should be let vc = segue.destinationViewController as RestaurantViewController, as long as RestaurantViewControlleris a subclass of UITableViewController. You'll crash if you try to cast it as a UINavigationController. Also make sure that the class for the destination UITableViewControllerin the storyboard is listed as RestaurantControllerin the Identity Inspector pane. You'll crash if your program compiles thinking that the storyboard just contains a generic UITableViewControllerthere.

@Starscream 有正确的想法,使用正确的标识符将正确的单元格出列,并将其与 Interface Builder 中的原型单元格的标识符相匹配。执行此操作后您遇到的崩溃可能是由于上述评论中提到的先前问题。您在情节提要中的 segue 显然指向UITableViewController. 您的代码prepareForSegue:sender:应该是let vc = segue.destinationViewController as RestaurantViewController,只要RestaurantViewController是 的子类UITableViewController。如果您尝试将其转换为UINavigationController. 还要确保UITableViewController故事板中目的地的类RestaurantController在 Identity Inspector 窗格中列出。如果你的程序编译时认为故事板只包含一个泛型UITableViewController,你就会崩溃。

Getting back to the original problem more, I don't know how you've implemented tableView:cellForRowAtIndexPath:, which might be crucial. Maybe it's not so simple. Maybe you plan on handling many prototype cells or generate custom cells at runtime. In this case, one way to make this simple for you is to programmatically perform the segue when the user taps on a cell. Instead of using a specific prototype cell, make the segue a connection originating from the "Restauranger n?ra mig" UITableViewControllergoing to the RestaurantViewController. (Connect in Interface Builder by control-click dragging from the Table View Controller icon at the top of the first one over to the body of the second). You must give this segue an identifier in the Attributes Inspector pane to make this useful. Let's say it's "toRestaurant". Then at the end of your tableView:didSelectRowAtIndexPath:method, put this line of code: self.performSegueWithIdentifier("toRestaurant", sender: self). Now no matter what cell is selected in the table, this segue will always fire for you.

更多地回到最初的问题,我不知道你是如何实现的tableView:cellForRowAtIndexPath:,这可能是至关重要的。也许事情没那么简单。也许您计划在运行时处理许多原型单元格或生成自定义单元格。在这种情况下,为您简化此操作的一种方法是在用户点击单元格时以编程方式执行 segue。不使用特定的原型单元,而是使 segue 成为源自“Restauranger n?ra mig”的UITableViewController连接到RestaurantViewController. (通过按住 Control 单击从第一个顶部的 Table View Controller 图标拖动到第二个主体的方式在 Interface Builder 中进行连接)。您必须在 Attributes Inspector 窗格中为这个 segue 提供一个标识符,以使其有用。让我们说它是"toRestaurant"。然后在你的最后tableView:didSelectRowAtIndexPath:方法,把这行代码:self.performSegueWithIdentifier("toRestaurant", sender: self)。现在无论在表格中选择什么单元格,这个 segue 都会为你触发。

回答by KyleMassacre

Im going out on a whim here since I am just getting into swift right now but the way I do it in my prepareForSegue()is something like this:

我在这里一时兴起,因为我现在才刚刚进入 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
     }
    }

What it looks like to me is that you are calling the i variable which is kind of like a private variable inside a method of your class. You can do something like @Syed Tariq did with the selectRowvariable and set it above your class SomeController: UIViewController /*, maybe some more here? */ {and then sign the variable inside your

在我看来,您正在调用 i 变量,它有点像您类的方法中的私有变量。您可以像@Syed Tariq 那样对selectRow变量进行操作并将其设置在您的上方class SomeController: UIViewController /*, maybe some more here? */ {,然后在您的内部对变量进行签名

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    selectedRow = indexPath.row

}

method like above but both ways should work rather well.

像上面的方法,但两种方法都应该工作得很好。

回答by Starscream

Try creating cells like this in your cellForRowmethod:

尝试在您的cellForRow方法中创建这样的单元格:

let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath)

回答by Jo?o Henrique

I had the same problem and I found the solution to be:

我遇到了同样的问题,我发现解决方案是:

performSegueWithIdentifier("toViewDetails", sender: self)

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
    }
}

回答by Chamath Jeevan

You may need to get the selected cell index of the UItableview. Below code used the selected cell index (UItableview.indexPathForSelectedRow) to get a correct element of the array.

您可能需要获取 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)!]
    }
}