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

时间:2015-11-11 03:22:44

标签: ios swift uiviewcontroller tableview segue

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

我的目标是在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
    }
}

我不知道如何做到这一点。如果你能帮助我搞清楚,我真的很感激!谢谢!

3 个答案:

答案 0 :(得分:4)

首先,我假设您的 MyTableViewController 类符合 UITableViewDataSource UITableViewDelegate 协议,并且您已经'将您的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的子类,并且您已经声明并连接了两个IBOutlet,例如 imageView textLabel 分别。此外,确保您的TableCell正确地链接到故事板中 Identity Inspector 下的原型单元格。您的TableCell类应如下所示:

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

现在回到 MyTableVIewController 类。从你的代码中,我看到你正在构建一条线,让cell = ...' as' 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方法

我在这里简单解释一下。当您没有控制 - 将一个ViewController的场景中的segue拖动到Storyboard中的另一个场景时,可以使用 performSegueWithIdentifier 方法。这样,使用 performSegueWithIdentifier 方法将允许您在ViewController场景之间移动,只要您指定了您在故事板中设置的正确标识符&#39 ; 属性检查器。 '

现在,如果您使用的是Storyboard,则不需要 tableView:didSelectRowAtIndexPath 方法。 tableView:didSelectRowAtIndexPath 方法的作用是它告诉委托现在选择了指定的行,我们可以在其代码体内执行某些操作(如推送图像或文本到另一个ViewController场景,就像你正在尝试做的那样)。但是当你使用segues时,这就变得多余了。您所要做的就是控制 - 拖动 MyTableViewController 场景到 myViewController 场景。选择' 显示'并为 segue 提供 标识符 这样的名称,就像您已经完成了" next &#34 ;. (一点注意事项:如果您希望在运行应用时在顶部导航栏中显示 后退 按钮功能,则只需嵌入您的 UINavigationController 中的 MyTableViewController ,为您提供' 返回 '按钮功能。在故事板中选择 MyTableViewController 场景,转到顶部菜单并选择 编辑器>>嵌入>>导航控制器 。然后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 '在您使用' destinationVC ' 现在是myViewController类型。这两个属性将保存我们从 MyTableViewController 类传递到 myViewController 类的数据。我们正在使用数组索引相应地将数据传递给这两个属性。

然后,您可以通过传递这些设置' imageName2 '来创建两个IBOutlet来显示您的图像和文本。和' textName2 '您的网点的属性(或任何UI控件)。

  • 现在你必须先设置属性的原因 myViewController 类,然后在它上面或周围传递它们(即到 当你从中查看tableView单元格时,UI元素,闭包,另一个VC等) MyTableViewController 场景到 segue 到你的下一个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(){})
  • 类和属性应该捕获它们的含义 代表。我建议你改变你的 MyTableViewController 和' myViewController '课程相应地反映了他们的真实情况 是或做(你可以使用' MainTableViewController'以及' DetailViewController'。这样就可以了。)
  • 对属性和方法使用camelToe标记。 (我用过你的标签 在你的问题中提供,以免过多地混淆你。)

    享受!

答案 1 :(得分:2)

这应该有所帮助:

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变量命名约定是camelCase,因此imageView是正确的方法,而ImageView不正确。

答案 2 :(得分:1)

在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()
}