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

我有两个文件,MyTableViewController和myViewController。 我在MyTableVIewController的TableCell上设置了UIImageView。 myViewController不包含任何东西。 我创build了一个名为ImageArray的数组,其中包含一个Images数组。

我打算在这里做的是当我点击myCableViewController中的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 } } 

我不知道该怎么做才能做到这一点。 我真的很感激,如果你能帮我弄明白! 谢谢!

首先,我假设您的MyTableViewController类符合UITableViewDataSourceUITableViewDelegate协议,并且您已将MyTableViewController类设置为代码中的代理或Storyboard。

整理完成后,有多种方法可以实现您所寻求的结果。 你可以声明你的ImageArray在一个独立的类中,并在MyTableViewController类中调用它,使用tableView委托方法将它们索引到tableView中,最后使用prepareForSegue方法将图像推送到myViewController上。 或者你可以简单地声明和初始化你的MyTableViewController类的顶部的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的子类,你已经声明和连接了两个IBOutlets,分别 imageViewtextLabel 。 此外,确保您的TableCell正确链接到您的原型单元格中的情节板下的身份检查器 )您的TableCell类应该看起来如下所示:

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

现在回到MyTableVIewController类。 从你的代码中,我看到你正在将'let cell = …'这行代码转换为'UITableViewCell。 您应该将其转换为“TableCell”,而不是将其转换为子类。 实现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方法的时间和地点有些困惑,而不是使用prepareForSegue方法。 甚至何时使用tableView:didSelectRowAtIndexPath方法

让我在这里简单解释一下。 当你没有控制时,你可以使用performSegueWithIdentifier方法,从一个ViewController的场景中拖拽一个Segue到另一个Storyboard。 这样,使用performSegueWithIdentifier方法将允许您在ViewController场景之间移动,只要您在“ 属性检查器 ”下的Storyboard中指定了正确的标识符即可

现在,如果您正在使用Storyboard,则不需要tableView:didSelectRowAtIndexPath方法。 tableView:didSelectRowAtIndexPath方法的作用是告诉委托,现在select了指定的行,并且我们可以在其代码体内执行某些操作(如将图像或文本推送到另一个ViewController Scene,就像你正在做的那样)。 但是,当你使用segues时,这变得多余。 所有你需要做的就是从你的MyTableViewController场景的表格单元格中 控制一个segue到你的myViewController场景。 select“ 显示 ”,并给你一个标识符名称,就像你已经完成“ 下一步 ”。 ( 有一点需要注意的是,如果你希望在运行应用程序时在顶部导航条上显示“ 返回 ”buttonfunction,只需将MyTableViewControllerembedded到UINavigationController中即可获得“ 返回 ”buttonfunction。在故事板中selectMyTableViewController场景,转到顶部菜单,select编辑器>>embedded>>导航控制器 ,然后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 } 

从上面的代码中,请确保在myViewController类中首先将“ imageName ”和“ textName ”设置为属性 ,然后才能通过“ destinationVC ”(它现在是myViewControllertypes)访问它们。 这两个属性将把我们从MyTableViewController类传递到myViewController类的数据保存起来 。 我们正在使用数组索引来相应地将数据传递给这两个属性。

然后,您可以创build两个IBOutlet,通过将这些设置的“ imageName2 ”和“ textName2 ”属性传递给您的sockets(或任何用于该事项的UI控件)来显示图像和文本。

  • 现在,为什么你必须在myViewController类中先设置属性,然后再传递它们(例如,到一个UI元素,闭包,另一个VC等),当你从MyTableViewController场景中击中tableView单元格,下一个ViewController场景(即你的myViewController场景),iOS还没有实例化第二个场景。 所以你需要一个属性来保存你想要传递给你的第二个场景View Controller的数据,以便以后在这个类最终加载时使用它。

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

 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中关于标签和约定的注意事项:

  • 开始使用块字母命名类(即类ViewController(){})
  • 类和属性应该捕捉它们所代表的含义。 我会build议你相应地改变你的MyTableViewController和' myViewController '类,以反映他们真正的意思或做什么(你可以使用'MainTableViewController'和'DetailViewController',这将会很好)。
  • 使用骆驼标签的属性和方法。 (我使用了你在问题中提供的标签,以免混淆太多)。

    请享用!

这应该有助于:

 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. 另外,Swiftvariables的命名约定是camelCase,所以imageView是正确的方法,而ImageView是不正确的。

在swift 3中你可以做这样的事情:

在你的MyTableViewController类中:

 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 myViewController: UIViewController { let myImageView = UIImageView() let myLabel = UILabel() }