在 Swift 中的视图控制器之间传递数据(从 TableView 到 DetailViewController)

Passing data between View Controllers in Swift (From TableView to DetailViewController)

我有两个文件,MyTableViewController 和 myViewController。我在 MyTableVIewController 的 TableCell 上设置了 UIImageView。 myViewController 不包含任何内容。我创建了一个名为 ImageArray 的数组,其中包含一个图像数组。

我在这里的目的是当我在 myTableViewController 中单击 TableCell 上的图像时,我希望单击的图像出现在 myViewController 中。在图片旁边还有一些关于点击图片的描述。我想为用户使用 myViewController 来获取所选图像的详细信息。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
    var ImageView = cell.viewWithTag(1) as! UIImageView
    ImageView.image = UIImage(named: ImageArray[indexPath.row])
    ImageView.contentMode = .ScaleAspectFit

    var TextView = cell.viewWithTag(2) as! UILabel
    TextView.text = ImageArray[indexPath.row]
    return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    performSegueWithIdentifier("next", sender: indexPath)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "next") {
        let destination = segue.destinationViewController as! myViewController
    }
}

我不知道该怎么做才能让它发生。如果你能帮我弄清楚,我真的很感激!谢谢!

这应该有帮助:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "next") {
        let destination = segue.destinationViewController as! myViewController
        destination.imageView.image = UIImage(named: ImageArray[tableView.indexPathForSelectedRow?.row])
        destination.textView.text = ImageArray[tableView.indexPathForSelectedRow?.row]
    }

}

(其中 imageView 和 textView 是新 viewController 中的视图。)

注:

  1. tableView.indexPathForSelectedRow?.row应该给你选中的行,顾名思义,但也可以是nil,所以要小心。
  2. 另外,Swift变量命名约定是驼峰式命名,所以imageView是正确的方式,而ImageView是不正确的。

首先,我假设您的 MyTableViewController class 符合 UITableViewDataSourceUITableViewDelegate 协议,并且您已将 MyTableViewController class 设置为代码中的委托或通过情节提要。

经过整理,有多种方法可以达到您想要的结果。 您可以在独立的 class 中声明您的 ImageArray 并在您的 MyTableViewController class 中调用它,使用 tableView 委托方法将它们索引到 tableView,最后使用 prepareForSegue 方法将您的图像推送到您的 myViewController。或者您可以简单地在 MyTableViewController class 的顶部声明并初始化您的 ImageArray,如下所示:

var ImageArray = [("Moscow Russia.jpg", "Europe"),
    ("London England.jpg", "Europe")]  

在上面的 ImageArray 中,确保您的图像名称与您导入到 Xcode 项目中的资产名称完全匹配。

然后我们指定需要 ImageArray 在我们的 tableView 中占据多少行(即基本上将我们的 ImageArray 计入我们的 TableView),使用以下所需的方法:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    return ImageArray.count ?? 0
}

接下来,您要使用 tableView:cellForRowAtIndexPath: 方法在单元格的每一行中显示您的 ImageArray

关于您的 TableCell 的旁注: 希望您的 TableCell 是从 UITableViewCell 子class编辑的,并且您已经声明并连接了两个 IBOutlet,比如说, imageViewtextLabel 分别。此外,请确保您的 TableCell 已正确链接到 Storyboard 中 Identity Inspector 下的原型单元格)您的 TableCell class 应如下所示:

import UIKit
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textLabel: UILabel!
}

现在回到您的 MyTableVIewController class。从您的代码中,我看到您将行 'let cell = ...' 转换为 'UITableViewCell。您应该将其转换为 'TableCell',因为您正在对它进行子class。实现 tableView:cellForRowAtIndexPath: 方法如下:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{        
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! TableCell

//Note that I'm using tuples here. Pretty cool huh. Got to love Swift!
  let (imageName, textNameToGoWithImage) = ImageArray[indexPath.row]

    cell.textLabel.text = textNameToGoWithImage
    cell.imageView.image = UIImage(named: imageName)
    cell.imageView.contentMode = .ScaleAspectFit

// You could have also used 'if let' in optional binding to safely unwrap your image if you want like below.
   //    if let image = UIImage(named: imageName){
   //        cell.imageView?.image = image
  //         cell.imageView.contentMode = .ScaleAspectFit
  //     }

    return cell
}

看起来您对何时何地使用 performSegueWithIdentifier 方法而不是使用 -[=106 有点困惑=]prepareForSegue 方法。甚至什么时候使用 tableView:didSelectRowAtIndexPath 方法

这里简单说明一下。当您没有控制拖动 segue 从一个 ViewController 的场景到情节提要中的另一个场景时,您可以使用 performSegueWithIdentifier 方法。这样,使用 performSegueWithIdentifier 方法将允许您在 ViewController 场景之间移动,只要您指定正确的标识符即可已在“Attributes Inspector.'

下的故事板中设置

现在,如果您改用 Storyboard,则不需要 tableView:didSelectRowAtIndexPath 方法。 tableView:didSelectRowAtIndexPath 方法的作用是告诉代理指定的行现在是 selected我们可以在它的代码体内做一些事情(比如将图像或文本推送到另一个 ViewController 场景,就像你想做的那样)。但是当你使用 segues 时,这就变得多余了。您所要做的就是 control-drag a segue table cell 在你的 MyTableViewController 场景到你的 myViewController 场景。选择'Show'并给segue一个标识符 命名为“next”。 (一点旁注: 如果您希望 后退 按钮功能显示在顶部导航栏你 运行 你的应用程序,你只需将你的 MyTableViewController 嵌入 UINavigationController 给你'Back' 按钮功能。使用您的 MyTableViewController 场景 select在 Storyboard 中编辑,转到顶部菜单和 select Editor >> Embed In >> Navigation Controller。然后 walla!! )

现在让我们继续实施我们的 tableView:prepareForSegue 方法,如下所示:

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "next" {
        //Note that, originally, destinationViewController is of Type UIViewController and has to be casted as myViewController instead since that's the ViewController we trying to go to. 
        let destinationVC = segue.destinationViewController as! myViewController


        if let indexPath = self.tableView.indexPathForSelectedRow{

            let selectedRow = ImageArray[indexPath.row]

            destinationVC.imageName2 = selectedRow.0
            destinationVC.textName2 = selectedRow.1
}

从上面的代码中,确保将“imageName”和“textName”设置为 properties 在您的 myViewController class 中,然后您才能使用 'destinationVC' 现在是 myViewController 类型。这两个属性将保存我们从 MyTableViewController class 传递到 myViewController class。我们正在使用数组索引将数据相应地传递给这两个属性。

然后您可以创建两个 IBOutlets 来显示您的图像和文本,方法是将这些设置的“imageName2”和“textName2”属性传递给您的网点(或任何 UI 控件)。

  • 现在您必须首先设置属性的原因是 myViewController class 在你传递它们之前或周围(即传递给 UI 元素、闭包、另一个 VC 等)是这样的,当您点击 tableView 单元格时 MyTableViewController 场景到 segue 到你的下一个 ViewController 场景(即您的 myViewController 场景),iOS 尚未实例化 第二个场景。所以你需要一个 属性 来保存数据 你试图首先传递到你的第二个场景视图控制器,这样你就可以 稍后在 class 最终加载时使用它。

所以你的 myViewController class 应该如下所示:

import UIKit

class myViewController : UIViewController {

   //Your two strings to initially hold onto the data 
  //being passed to myViewController class
var imageName2 : String?
var textName2 : String?

@IBOutlet weak var detailImageView: UIImageView!
@IBOutlet weak var detailTextNameLabel: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    detailTextNameLabel.text = textName2!

    if let image = UIImage(named: imageName2!) {
        self.detailImageView.image = image
    }
}

就是这样!

Swift中标签和约定的注意事项:

  • 开始用正楷命名 classes(即 class ViewController() {})
  • 类 和属性应该捕捉它们的含义 代表。我建议您更改 MyTableViewController 并且“我的ViewController”class相应地反映了他们的真实情况 意思或做(你可以选择 'MainTableViewController' 和 'DetailViewController'。这样就可以了)。
  • 对属性和方法使用 camelToe 标签。 (我用了你的标签 在您的问题中提供,以免让您感到困惑。

    尽情享受吧!

在 swift 3 你可以这样做:

在你的 MyTableViewController class:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! UITableViewCell

    // for imageview

    var ImageView : UIImageView = cell.contentView.viewWithTag(1) as! UIImageView
    ImageView.image = UIImage(named: ImageArray[indexPath.row])


    // for text

    var TextView : UILabel = cell.contentView.viewWithTag(2) as! UILabel
    ImageView.text = ImageArray[indexPath.row]

    return cell
}

并且在您的 didSelectRow 方法中:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
   let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "myViewController") as! myViewController
   nextVC.myImgView.image = UIImame(named: ImageArray[indexPath.row])
   nextVC.myLabel.text = ImageArray[indexPath.row]
   self.present(nextVC!, animated: true)
}

并在myViewController class:

class myViewController: UIViewController
{
    let myImageView = UIImageView()
    let myLabel = UILabel()
}